最简单的方式形成两个对象列表的联合(包含Int和字符串值)

本文关键字:包含 Int 字符串 两个 方式形 对象 最简单 列表 | 更新日期: 2023-09-27 17:54:33

我在这里看到一个类似的问题,有一个非常好的解决方案:形成两个列表并集的最简单方法

但是这里的问题是,当每个列表中只有一个形参(int value)时,它可以工作。我需要组合5个不同的列表,包含相同类的对象,没有数据冗余,最终列表应该按照int值的升序排序。

的例子:

Class Company   //data Class
{
int companyNo;
string Name;
}
Class CompanyList : List<Company>
{
  .................
  public CompanyList GetList(int userID)
  {
    .....
  }
}

类company有一个公共方法,返回与搜索条件相对应的公司列表,让我们userID。

CompanyList list1 = CompanyList .GetList(userID1);
CompanyList list2 = CompanyList .GetList(userID2);
CompanyList list3 = CompanyList .GetList(userID3);
CompanyList list4 = CompanyList .GetList(userID4);
CompanyList list5 = CompanyList .GetList(userID5);
The solution I implemented is (worked well):
CompanyList _finalList = list1;
*foreach (CompanyList _list in {_list2 ,_list3 ,_list4 ,_list5}) //loop thorugh all other list
{
   foreach (Company item in _list)
   {
      for (int i = 0; i <= _finalList.Count - 1; i++) 
      {
         if (_finalList.Item(i).CompanyNo== item.CompanyNo)
         //***EXIT TAKE NEXT LIST - GO TO *
      }
      if (i == _finalList.Count - 1)  //else check end of first list
      {
        //company no. not yet encountered(new)
        int pos = 0;
        foreach (Company companyInfo in _finalList) //search for position for new company no.
        {
          if (companyInfo.CompanyNo> item.CompanyNo) 
          {
             break;
          } 
          else 
          {
             pos = pos + 1; //increment position
           }
       }
      _finalList.Insert(pos, item); 'Add new item
    }
}
}

**的代码是从VB转换过来的。Net到c#。在这里,我找不到这一行对应的代码段,所以用概念代替了它。

我不是c#编程专家,只是想知道是否有更好或更简单的方法来做到这一点?

数据的例子:

Input:
list1[0] = {0,"TCS"};
list1[1] = {1,"Infosys"};
list2[0] = {8,"IBM"};
list3[1] = {1,"Infosys"};
list4[0] = {0,"TCS"};
list5[0] = {9,"Accenture"};
list5[1] = {6,"HCL"};
Output:
finalList[0] = {0,"TCS"};
finalList[1] = {1,"Infosys"};
finalList[2] = {6,"HCL"};
finalList[3] = {8,"IBM"};
finalList[4] = {9,"Accenture"};

的问候Sj

最简单的方式形成两个对象列表的联合(包含Int和字符串值)

好的,那么你有一些东西的序列,在你的例子中,"某事"将是Company,它不覆盖object.Equalsobject.HashCode

所以,像这样的一个新的扩展,可能是有用的

public static IEnumerable<T> Union(
    this IEnumerable<T> source,
    IEqualityComparer<T> comparer,
    params IEnumerable<T>[] others)
{
    if (comparer == null)
    {
        comparer = EqualityComparer<T>.Default;
    }
    var result = source.Distinct(comparer); 
    foreach(var o in source)
    {
        if (o == null)
        {
            continue;
        }
        result = result.Union(o, comparer);
    }
    return result;
}

要使这个和其他使用IEqualityComparer的函数易于使用,可以将这个类添加到代码中,

public class EqualityComparerImproved<T> : EqaulityComparer<T>
{
    private readonly Func<T, T> equalityComparison;
    private readonly Func<T, int> hashGenerator;
    private EqualityComparerImproved(
             Func<T, T> equalityComparison,
             Func<T, int> hashGenerator)
    {
        this.equalityComparison = equalityComparison;
        this.hashGenerator = hashGenerator;
    }
    public static EqualityComparerImproved<T> Create
             Func<T, T> equalityComparison,
             Func<T, int> hashGenerator)
    {
         if (equalityComparison == null)
         {
             throw new ArgumentNullException("equalityComparison");
         }
         if (hashGenerator == null)
         {
             throw new ArgumentNullException("hashGenerator");
         }
         return new EqualityComparerImproved<T>(
             equalityComparison,
             hashGenerator);
    }
    public override bool Equals(T x, T y)
    {
        return this.equalityComparison(x, y);
    }
    public override int GetHashCode(T obj)
    {
        return this.hashGenerator(obj);
    }
}

一旦这两段代码(诚然很长)就位,你就可以执行

var output = list1.Union(
    EqualityComparerImproved<Company>.Create(
        (x, y) => x.companyNo == y.companyNo && x.Name == y.Name,
        (obj) =>
            {
                unchecked // Overflow is fine, just wrap
                {
                    int hash = 17;
                    hash = hash * 23 + obj.companyNo;
                    hash = hash * 23 + obj.Name.GetHashCode();
                    return hash;
                }
            },
    list2,
    list3,
    list4,
    list5);

或者如果companyNo是唯一键,

var output = list1.Union(
    EqualityComparerImproved<Company>.Create(
        (x, y) => x.companyNo == y.companyNo,
        (obj) => obj.companyNo),
    list2,
    list3,
    list4,
    list5);

与Habib的解决方案类似,但更简洁和完整。

int[] userIDs = new[] { userID1, userID2, userID3, userID4, userID5 };
IEnumerable<Company> distinctCompanies =
    from companyList in userIDs.Select(CompanyList.GetList)
    from company in companyList
    group company by company.companyNo into companiesWithSameNo
    select companiesWithSameNo.First();
CompanyList finalList = new CompanyList();
finalList.AddRange(distinctCompanies);

您可能在CompanyList中也有一个直接接受IEnumerable<Company>的构造函数,因此您可以直接在那里传递distinctCompanies

您可以使用GroupBy或Union来删除重复项…(我认为)工会可以使路线更清晰,但两者都可以…缺点是,你还需要一个自定义的IEqualityComparer在这种情况下,因为等于你的公司对象将返回false(因为他们是不同的实例)…另一种选择是让您的Company类实现IEqualityComparer,并将我实现该接口的代码复制到您的Company类中。

// Union gives you a unique list if it knows how to compare the objects properly
var companyEqualityComparer = new CompanyEqualityComparer();
foreach (var companyList in new List<List<Company>>(){list2, list3, list4, list5})
{
    combinedList = combinedList.Union(companyList, companyEqualityComparer);
}
// Order your output list
var finalList = combinedList.OrderBy(c => c.companyNo).ToList();

定义你的companyqualitycomparer…

// CompanyEqualityComparer which is needed since your companies are different instances
public class CompanyEqualityComparer : IEqualityComparer<Company>
{
    public bool Equals(Company x, Company y)
    {
        return x.companyNo.Equals(y.companyNo);
    }
    public int GetHashCode(Company obj)
    {
        return obj.companyNo.GetHashCode();
    }
}

我想你需要这样的东西:

List<Company> inputList = //Get your input List
List<Company> outputList = inputList.GroupBy(r => r.companyNo)
                                    .Select(grp => new Company
                                        {
                                            companyNo = grp.Key,
                                            Name = grp.First().Name,
                                        })
                                    .OrderBy(r=> r.companyNo)
                                    .ToList();