【问题标题】:C# order a list by another list and add the ones that weren't found to the end of the listC# 按另一个列表对列表进行排序,并将未找到的列表添加到列表末尾
【发布时间】:2014-09-25 08:15:27
【问题描述】:

我有一个值列表,用于对另一个值列表进行排序,但我一直遇到的问题是,如果我删除 2 个要排序的值,则需要的值列表中的两个值要排序的值丢失了这两个值,因为在排序值列表中找不到它。

这是我的尝试示例

尝试 1

universites = universites.OrderBy(d => listOrderedUniversites.IndexOf(d)).ToList();

universites 是一个 List,orderedUniversity 是一个模型的列表,listOrderedUniversites 是一个 List。

然而,这确实提取了所有值,但根本没有对它们进行排序。

--- 更新---

这就是我所拥有的

universites = new List<SelectListItem>();
universites.Add( new SelectListItem()
{
    Value = 1,
    Test = "University 1"
});
universites.Add( new SelectListItem()
{
    Value = 2,
    Test = "University 2"
});
universites.Add( new SelectListItem()
{
    Value = 3,
    Test = "University 3"
});

ordering = new int[] {3, 1, 2};

所以我需要按 int 数组排序我的 List;

【问题讨论】:

  • 您能否提供样本清单以及预期结果?您的问题目前有点不清楚,因为如果它们的长度不同,我看不出如何将一个列表按另一个列表排序,以及为什么一个列表中的项目也应该在另一个列表中。
  • 什么是d?它是University 的一类吗?如果是,您是否覆盖了此类的EqualsGetHashCode
  • @Matthew 好的,可以说 orderedUniversities 是 {1,5,4,2,3} 而大学是 {1,2,3,4,5,6,7} 我想订购大学看起来像 {1,5,4,2,3,6,7},列表长度可能不同的原因是我从数据库中提取它们并且该表可以在添加值时增加,以便新的值需要添加到列表和有序列表中,否则它永远不会显示
  • 如果orderedUniversities 中的条目不在universities 中,应该怎么办?
  • 找不到该值,因此不会对其进行排序,因此该项目不会在列表中

标签: c# asp.net-mvc list


【解决方案1】:

我已经模拟了正确和错误的行为:

  List<String> universites = new List<String>() {
    "E", "A", "D", "C", "B"
  };

  // Desired order: A, C, D; X, Z will be ignored
  List<String> listOrderedUniversites = new List<String>() {
    "A", "C", "D", "X", "Z"
  };

  // result is "E, B, A, C, D":
  // "E" and "B" are not in listOrderedUniversites
  // and so IndexOf() returns -1 for such values 
  // that's why "E", "B" appears in the begining of the list
  // all the other items ("A", "C", "D") are sorted as expected
  String result = String.Join(", ",
    universites.OrderBy(item => listOrderedUniversites.IndexOf(item)));

但是,如果你用 StringBuilder 代替 String ,那么一切都会出错

  List<StringBuilder> universites = new List<StringBuilder>() {
    new StringBuilder("E"), 
    new StringBuilder("A"), 
    new StringBuilder("D"), 
    new StringBuilder("C"), 
    new StringBuilder("B")
  };

  List<StringBuilder> listOrderedUniversites = new List<StringBuilder>() {
    new StringBuilder("A"), 
    new StringBuilder("C"), 
    new StringBuilder("D"), 
    new StringBuilder("X"), 
    new StringBuilder("Z")
  };

  // Wrong order: "E, A, D, C, B" (note "A, D, C")
  String result = String.Join(", ", universites
    .OrderBy(item => listOrderedUniversites.IndexOf(item))
    .Select(item => item.ToString()));

原因是您必须重写 Equals()GetHashCode() 方法 让List.IndexOf() 正常工作。默认Equals()GetHashCode() 实现考虑实例地址(两个对象相等当且仅当它们实际上是对同一个实例的一个引用),而不是它们的值 em>。

【讨论】:

    【解决方案2】:

    [编辑] 这个问题太不清楚了,我不知道这是否是正确的答案。我不应该试图回答这个问题,但我会留在这里等待 OP 的澄清。

    您可以使用Enumerable.Intersect()Enumerable.Except() 执行此操作。

    这是一个使用整数演示它的可编译示例(为简单起见):

    using System;
    using System.Collections.Generic;
    using System.Linq;
    
    namespace Demo
    {
        internal class Program
        {
            private static void Main()
            {
                IEnumerable<int> ordered   = new [] {1, 5, 4, -1, 2, 3};
                IEnumerable<int> unordered = Enumerable.Range(1, 7);
    
                // This prints 1, 5, 4, 2, 3, 6, 7:
    
                Console.WriteLine(string.Join(", ", MyOrderBy(unordered, ordered)));
            }
    
            public static IEnumerable<T> MyOrderBy<T>(IEnumerable<T> unordered, IEnumerable<T> ordered)
            {
                return ordered.Intersect(unordered).Concat(unordered.Except(ordered));
            }
        }
    }
    

    请注意,这假定两个列表中都没有重复项。

    另请注意,要使Intersect()Except() 正常工作,元素的类型必须具有适合该类型的GetHashCode()Equals() 实现。

    这意味着为您的 University 类型正确覆盖它们。

    【讨论】:

    • 永远不会有重复,但是您可以为 List 和整数数组执行此操作吗?
    • @Canvas 因为我使用的是IEnumerable&lt;T&gt;,所以它适用于实现IEnumerable&lt;T&gt; 的任何东西,这几乎是所有集合类型,包括整数数组和List&lt;T&gt;。换句话说,您可以将列表和数组传递给上面显示的OrderBy() 方法。如果您希望返回类型为列表,只需在返回值上调用ToList()。同样,如果您想要一个数组,请致电ToArray()
    • 请注意以下 Dmitry 的 cmets:为了能够使用 Intersect()Except(),您必须能够正确比较项目,因此对于自定义类型,您需要覆盖 GetHashCode() 和 @该类型为 987654338@。
    • @Canvas 重新阅读您的 cmets,您的意思是要提供一个整数数组作为排序并使用它来排序具有不同类型的集合吗?这将是一个与您的 OP 非常不同的问题......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-02
    • 2021-01-23
    • 2012-10-31
    • 2011-03-22
    • 1970-01-01
    • 2012-02-08
    相关资源
    最近更新 更多