2011-06-13 48 views
1

我有一些不尋常的我需要做的。我想知道是否有人可以想到一個簡單的方法來做出我需要的改變。我已經是一個如何洗牌多個相關的數組?

public class Report 
    { 
     public string[] Text { get; set; } 
     public string[] Image { get; set; } 
     public string[] Explanation { get; set; } 
    } 

報告類可以有任意數量的文字,圖片和說明,並且每個數組的大小總是一致的,但也許是每個報表實例不同。

我需要做的是能夠以隨機順序對數組元素進行排序。因此,例如我可能有

Report.Text[0] = "text0"; 
Report.Text[1] = "text1"; 
Report.Text[2] = "text2"; 
Report.Image[0] = "img0"; 
Report.Image[1] = "img1"; 
Report.Image[2] = "img2"; 
Report.Explanation[0] = "exp0"; 
Report.Explanation[1] = "exp1"; 
Report.Explanation[2] = "exp2"; 

然後排序

Report.Text[0] = "text2"; 
Report.Text[1] = "text0"; 
Report.Text[2] = "text1"; 
Report.Image[0] = "img2"; 
Report.Image[1] = "img0"; 
Report.Image[2] = "img1"; 
Report.Explanation[0] = "exp2"; 
Report.Explanation[1] = "exp0"; 
Report.Explanation[2] = "exp1"; 

誰能想到一個簡單的方法來做到這一點後?我所能想到的是,我需要創建一個尺寸相同的新臨時對象,並進行某種交換。但我不知道如何 隨機。我問的原因是爲了防止過去有人有這種需求。

+0

我聽到第一次按隨機順序排序。同樣對於報告,我寧願使用命名屬性,像StringTemplate這樣的庫非常適合報告。不要在報告對象/類 – 2011-06-13 14:31:50

回答

5

我會強烈建議您重構此以創建一個類來封裝{ Text, Image, Explanation }元組。在那個時候,代碼將變得更加清晰,重新排列這些值將是微不足道的。哎,你可能甚至不需要Report類型在這一點上...你可能只能有一個List<ReportItem>或其他什麼。如果您想添加額外的行爲或數據來將事情聯繫在一起,您只需要一個單獨的Report類型。

(順便說一句,我希望你真的沒有公共字段,這些與...開始)

如果然後各地紛紛洗牌單個集合問題,修改Fisher-Yates shuffle是可能是最簡單的方法。你也可以用多個數組來做到這一點,但它不會很好 - 並且必須特定於Report ...而您可以很容易地編寫一個基於IList<T>的Fisher-Yates實現的通用。如果您對堆棧溢出進行搜索,你應該很容易就能找到一些已有的實現:)

+0

上同意保存操縱數據。它可能會讓你的所有代碼更清潔,而不僅僅是重新排序。 – Tim 2011-06-13 14:06:29

+1

雖然這是一個很好的建議,但它不回答OP的問題。 – 2011-06-13 14:07:17

+1

@阿德里安:這是我想要到達OP需要去的方法。 – 2011-06-13 14:08:13

0

你爲什麼不創建一個類

public class Report 
{ 
    public string Text { get; set; } 
    public string Image { get; set; } 
    public string Explanation { get; set; } 
} 

,然後創建這些對象的名單,並對其進行管理通過列表屬性:

IList<Report> yourList = new List<Report>() 
1

如果你選擇你的類更改爲以下:

public class Report 
{ 
    public string Text { get; set; } 
    public string Image { get; set; } 
    public string Explanation { get; set; } 
} 

然後,您可以做到這一點使用的擴展方法:

See answer on this SO question

然後調用這樣說:

List<Report> reports = new List<Report> { /* create list of reports */ } 
Random rnd = new Random(); 
foreach (Report r in reports.Shuffle(rnd)) { 
    /* do something with each report */ 
} 
+1

在每個呼叫中​​創建一個新的隨機'是一個壞主意IMO - 我個人並不喜歡這種洗牌方式,效率低下,取決於只能提取一次的密鑰.Fisher-Yates洗牌很容易實現,並且性能會更好,我會將Random '重視參數並使用o http://csharpindepth.com/Articles/Chapter12/Random.aspx中的方法來提供它。 – 2011-06-13 14:11:22

0

這裏是我的解決方案

class StringWrapper 
    { 
     public int Index; 
     public string Str; 
    } 

    public string[] MixArray(string[] array) 
    { 
     Random random = new Random(); 
     StringWrapper[] wrappedArray = WrapArray(array); 

     for (int i = 0; i < wrappedArray.Length; i++) 
     { 
      int randomIndex = random.Next(0, wrappedArray.Length - 1); 
      wrappedArray[i].Index = randomIndex; 
     } 

     Array.Sort(wrappedArray, (str1, str2) => str1.Index.CompareTo(str2.Index)); 
     return wrappedArray.Select(wrappedStr => wrappedStr.Str).ToArray(); 
    } 

    private StringWrapper[] WrapArray(string[] array) 
    { 
     int i = 0; 
     return array.Select(str => new StringWrapper {Index = ++i, Str = str}).ToArray(); 
    } 

然後就可以調用MixArray爲您的魔杖隨機化的每個屬性的每個報告對象。

+0

但對我來說問題是所有的數組需要按照我的示例中的相同順序進行隨機化。我不知道如何用你的方法做到這一點。 – Jennifer82 2011-06-13 14:31:54

0

我不知道我很喜歡這個方向,但是......

做的正是你的要求(法律,沒有法律的精神),你將不得不增加額外的陣列和拉項目結束。另外,對於每個陣列,您需要一個List或類似的存儲您已經隨機拉動的項目。之後,事情很簡單。使用Random類創建隨機數字,檢查項目是否已經移動(使用List),如果沒有將結果存儲到新的數組/列表中,請將值添加到List中以確保不會移動相同項目兩次。一旦移動了所有內容,將這個新數組設置爲舊數組。

現在,隨機化的商業原因是什麼?這可能會影響這是否是一個好主意。

新增:

飛碟雙向的迴應檢查後,這裏就是爲了解決這一點,如果你可以使用下列類型類的方式:

public class Report { 
    public string Text { get; set; } 
    public string Image { get; set; } 
    public string Explanation { get; set; } 
} 

這裏是一個「下來,髒」的類型排序:

private static SortedList<int, Report> SortRandomly(List<Report> reports) 
    { 
     Random rnd = new Random((int)DateTime.Now.Ticks); 
     List<int> usedNumbers = new List<int>(); 
     SortedList<int, Report> sortedReports = new SortedList<int, Report>(); 
     int maxValue = reports.Count; 

     foreach(Report report in reports) 
     { 
      bool finished = false; 
      int randomNumber = 0; 

      //Get unique random (refactor out?) 
      while(!finished) 
      { 

       randomNumber = rnd.Next(0, maxValue); 

       if(!usedNumbers.Contains(randomNumber)) 
       { 
        finished = true; 
        usedNumbers.Add(randomNumber); 
       } 
      } 

      sortedReports.Add(randomNumber, report); 
     } 

     return sortedReports; 
    } 

注意,你也可以工作,以保持排序順序和從原來的列表,這意味着你可以在理論上,把它作爲一個列表中隨機挑選。

private static List<Report> SortRandomly(List<Report> reports) 
    { 
     Random rnd = new Random((int)DateTime.Now.Ticks); 
     List<Report> outputList = new List<Report>(); 
     List<int> usedNumbers = new List<int>(); 
     int maxValue = reports.Count-1; 

     while(outputList.Count < reports.Count) 
     { 
      int randomNumber = rnd.Next(0, maxValue); 

      if(!usedNumbers.Contains(randomNumber)) 
      { 
       outputList.Add(reports[randomNumber]); 
      } 
     } 

     return outputList; 
    } 

更好的是,考慮先排序數字列表,然後按順序抓取報告。再一次,上述情況已經下降,並且骯髒的實現和使用特定的要求肯定會改進算法。

+0

這幾乎是我的想法。企業希望每次用戶查看時都以不同的方式呈現報告信息。類似於在每個視圖上以隨機順序出現的表格行。 – Jennifer82 2011-06-13 14:21:38

+0

項目是否相同,這意味着text1與image1和exp1相關?如果是這樣,請考慮創建一個班級,然後您可以爲班級設置一個列表。有幾種隨機排序的方法。 – 2011-06-13 14:43:02