Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/295.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 给定所需的顺序,需要一个节省空间的列表重新排序或排序_C#_Algorithm_List_Sorting - Fatal编程技术网

C# 给定所需的顺序,需要一个节省空间的列表重新排序或排序

C# 给定所需的顺序,需要一个节省空间的列表重新排序或排序,c#,algorithm,list,sorting,C#,Algorithm,List,Sorting,我的目标是:给定条目列表和所需的顺序,根据该顺序重新排列条目列表。列表将非常大,因此空间效率非常重要 例: 我可能弄错了,但似乎最直接、最节省空间的解决方案是按顺序对数据进行排序/排序。或者更一般地说: 给出两个列表:A,B有办法按B对A排序吗?功能基本上与以下相同: Array.Sortarray[],Array[][] 想到的一种方法是创建由a和B组成的新数据类型,即配对,然后按B值排序: List<T> A; List<T> B; Assert(A.Count ==

我的目标是:给定条目列表和所需的顺序,根据该顺序重新排列条目列表。列表将非常大,因此空间效率非常重要

例:

我可能弄错了,但似乎最直接、最节省空间的解决方案是按顺序对数据进行排序/排序。或者更一般地说:

给出两个列表:A,B有办法按B对A排序吗?功能基本上与以下相同: Array.Sortarray[],Array[][]

想到的一种方法是创建由a和B组成的新数据类型,即配对,然后按B值排序:

List<T> A;
List<T> B;
Assert(A.Count == B.Count);
var C = A.Select( (a,idx) => new Pair<T,T>(B[idx],a)).OrderBy(c => c.First);
A = C.Select(x => x.Second).ToList();

然而,我希望这是尽可能节省空间的选择和收费电话我猜都是昂贵的,所以一个基本上就地排序是必要的。为此,有没有一种方法可以为引用B的a.Sort编写一个比较器

最有效的重新排序算法可能是某种形式的惰性计算。您可以创建一个IList实现,该实现使用数据列表和排序列表从实际重新排序的序列中动态返回值,而不是以新的顺序重新计算序列

惰性模型的好处是,执行双重查找在性能方面可以忽略不计,并且不需要重新排序整个列表以开始返回值。它还可能允许相同的值列表以多个顺序显示,而无需重复基础列表。当然,如果希望确保对原始列表或排序的更改不会影响动态排序的列表,可以将实现更改为复制列表

下面是一个未经测试的代码示例

注意:为了简单起见,我对示例中的实现做了一些修改,使用了基于0的索引,而不是基于1的索引。但是,如果需要的话,可以很容易地将代码转换为使用基于1的索引

如果需要将动态排序的列表具体化为常规列表,则可以使用以下方法,这些方法将按时运行,并且不会创建不必要的数据副本:

var staticallyOrderedList = originalList.ReorderBy( ordering ).ToList();

有两种方法可以解释order数组,一种是列出每个元素的源索引,另一种是列出每个元素的目标索引。我不知道你指的是哪一个

给目的地列表重新排序非常简单:

// Sets list[destination[i]] = list[i] for all i.  Clobbers destination list.
void ReorderByDestination(List<T> list, List<int> destination) {
  for (int i = 0; i < list.Count; i++) {
    while (destination[i] != i) {
      int d = destination[i];
      T t = list[d];            // save element in destination slot
      int t_d = destination[d]; // and its own destination
      list[d] = list[i];        // move element to destination
      destination[d] = d;       // and mark it as moved
      list[i] = t;              // store saved element in slot i
      destination[i] = t_d;     // ... and its destination
    }
  }
}
给一个列表重新排序给定一个源列表,这是我认为你想要的,这有点困难,你只需要先反转排列

// Sets list[i] = list[source[i]] for all i.  Clobbers source list.
void ReorderBySource(List<T> list, List<int> source) {
  InvertPermutation(source);
  ReorderByDestination(list, source);
}
有一些已知的置换反转例程,我发现的第一个是perm_inv in


通常,您不需要反转排列,而是修改生成源列表的内容以生成目标列表。

Reflector、profiler是您的朋友。否。OrderBy将在IOrderedEnumerable第一次迭代时创建一个临时文件来存储排序。@Jason:我有一个输入错误,我的意思是在最后一个代码段中使用ReorderBy排序,而不是OrderBy排序,它甚至不会编译。@LBushkin:正如我所说的那样。我喜欢你博客上的两篇文章。我也是一个很爱玩拼图的人。你应该认真考虑张贴更多。杰森:不知道为什么,所以我不会让你投票。至于我的博客,很快就会有更多的内容,我最近工作很忙,所以我不得不给一些东西。@LBushkin:它只是说投票太旧了,不能改变,除非这个答案被编辑。但我对你的职位没有投票权。工作:我知道这种感觉。
var staticallyOrderedList = originalList.ReorderBy( ordering ).ToList();
// Sets list[destination[i]] = list[i] for all i.  Clobbers destination list.
void ReorderByDestination(List<T> list, List<int> destination) {
  for (int i = 0; i < list.Count; i++) {
    while (destination[i] != i) {
      int d = destination[i];
      T t = list[d];            // save element in destination slot
      int t_d = destination[d]; // and its own destination
      list[d] = list[i];        // move element to destination
      destination[d] = d;       // and mark it as moved
      list[i] = t;              // store saved element in slot i
      destination[i] = t_d;     // ... and its destination
    }
  }
}
// Sets list[i] = list[source[i]] for all i.  Clobbers source list.
void ReorderBySource(List<T> list, List<int> source) {
  InvertPermutation(source);
  ReorderByDestination(list, source);
}