【问题标题】:C# - Fastest Way To Sort Array Of Primitives And Track Their IndicesC# - 对基元数组进行排序并跟踪其索引的最快方法
【发布时间】:2013-06-28 07:19:45
【问题描述】:

我需要一个float[] 进行排序。我需要知道旧索引在新数组中的位置。这就是为什么我不能使用Array.Sort(); 或其他什么。所以我想写一个函数来为我排序数组并记住它从哪个索引中获取每个值:

float[] input  = new float[] {1.5, 2, 0, 0.4, -1, 96, -56, 8, -45};
// sort
float[] output; // {-56, -45, -1, 0, 0.4, 1.5, 2, 8, 96};
int[] indices; // {6, 8, 4, 2, 3, 0, 1, 7, 5};

数组的大小约为 500。我应该如何处理这个?什么排序算法等等。


解决后: C# 的强大总是让我感到惊讶。我什至不认为它能够自己完成这项任务。因为我已经听说Array.Sort() 非常快,所以我会接受它。

【问题讨论】:

  • 关于索引...保存输入列表,对输出进行排序,然后比较两者之间的索引不是更容易吗? float 和 int 之间的内存没有大小差异,因此不会占用任何内存。
  • @Tophe 你确定这是最快的方法吗?
  • 不确定,也没有公认的答案那么巧妙。但是根据您需要获取原始索引的频率,实际比较索引可能更有效,而不是在创建时遍历每个列表 - 因为输入列表已经包含原始索引。这让你每次都少做一条指令。不过,您可能会以更流畅的方式获取其他方式的值。

标签: c# performance sorting primitive


【解决方案1】:
float[] input = new float[] { 1.5F, 2, 0, 0.4F, -1, 96, -56, 8, -45 };
int[] indices = new int[input.Length];
for (int i = 0; i < indices.Length; i++) indices[i] = i;
Array.Sort(input, indices);
// input and indices are now at the desired exit state

基本上,Array.Sort 的 2 参数版本将相同的操作应用于 两个 数组,在第一个数组上运行实际的 sort 比较。这通常以相反的方式使用 - 通过所需的索引重新排列某些东西;但这也有效。

【讨论】:

  • 感谢没有Linq 的示例并提供了很好的解释。
  • A List> 和自定义排序器也可以使用
  • @tinstaafl 但会更复杂,需要复制原始数据(注意我从未复制过浮点数);实际上不会对原始数组进行排序;并且会不那么直接(通过比较器),因此我会 expect 性能较差(未验证)
【解决方案2】:

您可以使用 Array.Sort() 的重载,它接受两个数组,并根据对第一个数组的排序方式对第二个数组进行排序:

float[] input  = new [] { 1.5f, 2, 0, 0.4f, -1, 96, -56, 8, -45 };
int[] indices = Enumerable.Range(0, input.Length).ToArray();
Array.Sort(input, indices);

【讨论】:

    【解决方案3】:

    您可以创建一个新的索引数组,然后使用 Array.Sort 对它们进行排序并将input 视为键:

    float[] input = new float[] { 1.5F, 2, 0, 0.4F, -1, 96, -56, 8, -45 };
    int[] indicies = Enumerable.Range(0, input.Length).ToArray();
    Array.Sort(input, indicies);
    

    【讨论】:

      【解决方案4】:

      如果你使用 linq:

          float[] input = new float[] { 1.5F, 2, 0, 0.4F, -1, 96, -56, 8, -45 };
      
          var result = input.Select(x => new { Value = x, Index = input.ToList().IndexOf(x)}).OrderBy(x => x.Value).ToList();
      
          // sort
          float[] output = result.Select(x => x.Value).ToArray();
          int[] indices = result.Select(x => x.Index).ToArray();
      

      在结果中,您得到了具有值及其索引的对象。

      【讨论】:

      • 您意识到input.ToList 每个输入元素,如果有重复则无法给出正确的结果?实际上有一个Select 的重载交给你每个项目的索引 - .Select((x,i) =&gt; new { Value = x, Index = i }) 会好得多。但在这种情况下,无论如何,Array.Sort 就足够了。
      【解决方案5】:

      List&lt;KeyValuePair&lt;int,float&gt;&gt; 和自定义排序器也可以使用。每对的键保存原始索引。

          private void Form1_Load(object sender, EventArgs e)
          {           
              List<KeyValuePair<int,float>> data = new List<KeyValuePair<int,float>>
              {
                   new KeyValuePair<int,float>(0,1.5f),
                   new KeyValuePair<int,float>(1,2),
                   new KeyValuePair<int,float>(2,0),
                   new KeyValuePair<int,float>(3,0.4f),
                   new KeyValuePair<int,float>(4,-1),
                   new KeyValuePair<int,float>(5,96),
                   new KeyValuePair<int,float>(6,-56),
                   new KeyValuePair<int,float>(7,8),
                   new KeyValuePair<int,float>(8,-45)
              };
              data.Sort(SortByValue);
              foreach (KeyValuePair<int, float> kv in data)
              {
                  listBox1.Items.Add(kv.Key.ToString() + " - " + kv.Value.ToString());
              }
      
      
          }
          private int SortByValue(KeyValuePair<int, float> a, KeyValuePair<int, float> b)
          {
              return a.Value.CompareTo(b.Value);
          }
      

      【讨论】:

        猜你喜欢
        • 2021-11-15
        • 1970-01-01
        • 1970-01-01
        • 2014-06-28
        • 2016-08-11
        • 2014-03-03
        • 1970-01-01
        • 2013-04-27
        • 2011-08-03
        相关资源
        最近更新 更多