从类型类

时间:2015-12-08 14:30:21

标签: c# list class duplicates

我有一个具有以下属性的类

id(类型:唯一long),name(类型:string),版本主要(VM)(类型:{{1} }),版本次要(long)(类型:Vm

我创建了这个类的列表,列表如下所示

long

我想根据Version Major和版本minor删除列表中的重复项。最终列表应如下所示

ID    Name     VM    Vm
1     ssim     2     1
2     SSim     3     1
3     Counter  5     1
4     Counter  6     2
5     Counter  6     5

5 个答案:

答案 0 :(得分:2)

这样的事情,我想:

public class Product
{
    public Product(long id, string name, int major, int minor)
    {
        this.Id = id;
        this.Name = name;
        this.Major = major;
        this.Minor = minor;
    }

    public long Id { get; set; }

    public int Major { get; set; }

    public int Minor { get; set; }

    public string Name { get; set; }
}

private static void Main()
{
    IEnumerable<Product> products = new List<Product>
                                    {
                                        new Product(1, "ssim", 2, 1),
                                        new Product(2, "SSim", 3, 1),
                                        new Product(3, "Counter", 5, 1),
                                        new Product(4, "Counter", 6, 2),
                                        new Product(5, "Counter", 6, 5)
                                    };

    IEnumerable<Product> distinctProducts =
        (from x in products group x by x.Name.ToLower() into g select g.OrderByDescending(y => y.Major).ThenByDescending(y => y.Minor).First()).OrderBy(x => x.Name).ToList();
}

答案 1 :(得分:2)

所以你想要每个名字的最大版本。

你可以像这样使用linq:

void Main()
{
    var versions = new List<Version>
    {
     new Version(1,2, "a"),
     new Version(1,3, "a"),
     new Version(1,3, "b"),
     new Version(1,4, "b"),
     new Version(1,1, "b"),
     new Version(2,3, "c")
    };

    var distinctVersions = versions
    .GroupBy(g => g.name.ToLowerInvariant())
    .Select(g => g.ToList().OrderBy(x => x.major).ThenBy(x => x.minor).Last())
    .ToList();
}

答案 2 :(得分:1)

说你的班级是ProgramEntry

public class ProgramEntry {

    public long Id;
    public string Name;
    public long VM;
    public long Vm;

    public ProgramEntry (long id, string name, long vM, long vm) {
        Id = id;
        Name = name;
        VM = vM;
        Vm = vm;
    }

    public override string ToString () {
        return this.Id+":"+this.Name+"("+this.VM+"."+this.Vm+")";
    }

}

(是的,使用公共字段不是一个好习惯,但只是一个快速而肮脏的解决方案)

现在您可以按版本(第一个主要版本,然后是次要版本)订购它们:

List<ProgramEntry> programs = new List<ProgramEntry>();
//fill list with programs
var order = programs.OrderBy(x => -x.VM).ThenBy(x => -x.Vm);

这会导致IEnumerable<ProgramEntry>排序最大的主要优先,如果是等同的主要,最大的次要优先。

接下来,您可以使用this duplicate filter过滤掉具有相同Name的元素:

List<ProgramEntry> result = order.DistinctBy(x => x.Name).ToList();

DistinctByMoreLINQ库的一部分。或者您可以使用扩展类

自行实现它
public static class Foo {

    public static IEnumerable<TSource> DistinctBy<TSource, TKey>
        (this IEnumerable<TSource> source, Func<TSource, TKey> keySelector) {
        HashSet<TKey> seenKeys = new HashSet<TKey>();
        foreach (TSource element in source) {
            if (seenKeys.Add(keySelector(element))) {
                yield return element;
            }
        }
    }

}

演示(使用csharp交互式shell):

$ csharp
Mono C# Shell, type "help;" for help

Enter statements below.
csharp> public class ProgramEntry {
      >  
      >     public long Id;
      >     public string Name;
      >     public long VM;
      >     public long Vm;
      >  
      >     public ProgramEntry (long id, string name, long vM, long vm) {
      >         Id = id;
      >         Name = name;
      >         VM = vM;
      >         Vm = vm;
      >     }
      >  
      >     public override string ToString () {
      >         return this.Id+":"+this.Name+"("+this.VM+"."+this.Vm+")";
      >     }
      >  
      > }
csharp> List<ProgramEntry> programs = new List<ProgramEntry>();
csharp> programs.Add(new ProgramEntry(1,"ssim",2,1));
csharp> programs.Add(new ProgramEntry(2,"ssim",3,1)); 
csharp> programs.Add(new ProgramEntry(3,"Counter",5,1));
csharp> programs.Add(new ProgramEntry(4,"Counter",6,2)); 
csharp> programs.Add(new ProgramEntry(5,"Counter",6,5)); 
csharp> programs
{ 1:ssim(2.1), 2:ssim(3.1), 3:Counter(5.1), 4:Counter(6.2), 5:Counter(6.5) }
csharp> var order = programs.OrderBy(x => -x.VM).ThenBy(x => -x.Vm);
csharp> order
{ 5:Counter(6.5), 4:Counter(6.2), 3:Counter(5.1), 2:ssim(3.1), 1:ssim(2.1) }
csharp> List<ProgramEntry> result = order.DistinctBy(x => x.Name).ToList();
csharp> result
{ 5:Counter(6.5), 2:ssim(3.1) }

这是预期的行为吗?

答案 3 :(得分:0)

我们假设这个类类似于你的数据:

public class VerX
{
    public int ID { get; set; }
    public string Name { get; set; }
    public int VerMajor { get; set; }
    public int VerMinor { get; set; }
}

对于您的样本,这是填充此数据的方式:

var list = new List<VerX>
{
    new VerX { ID = 1, Name = "ssim", VerMajor = 2, VerMinor = 1 },
    new VerX { ID = 2, Name = "SSim", VerMajor = 3, VerMinor = 1 },
    new VerX { ID = 3, Name = "Counter", VerMajor = 5, VerMinor = 1 },
    new VerX { ID = 4, Name = "Counter", VerMajor = 6, VerMinor = 2 },
    new VerX { ID = 5, Name = "Counter", VerMajor = 6, VerMinor = 5 },
};

现在,让我们创建一个循环,为您提供所需的结果:

// First create new list that would hold the results
var listNew = new List<VerX>();

// Select distinct names from data (using ToLower, so casing does not matter)
var names = list.Select(t => t.Name.ToLower()).Distinct().ToList();

// Loop through each of distinct name
foreach (var name in names)
{
    // With LINQ, select item whose name matches and sort list by VerMajor
    // descending and VerMinor descending and take first item.
    var item = list.Where(t => t.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase))
                   .OrderByDescending(t => t.VerMajor)
                   .ThenByDescending(t => t.VerMinor)
                   .FirstOrDefault();

    // If item not found (although it should be found!), continue the loop
    if (item == null)
        continue;

    // Add item to new list
    listNew.Add(item);
}

// At the end of the loop, the listNew contains items as in your proposed result.

可以通过更复杂的LINQ查询获得相同的foreach循环:

// Select distinct names as in first case
var names = list.Select(t => t.Name.ToLower()).Distinct().ToList();

// Construct listNew from names based on same algorithm as before, but using LINQ this time.
var listNew = names
    .Select(name => list.Where(t => t.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase))
                        .OrderByDescending(t => t.VerMajor)
                        .ThenByDescending(t => t.VerMinor)
                        .FirstOrDefault())
    .Where(item => item != null)
    .ToList();

 // Here, listNew contains your desired result.

根据您想要的结果,这会根据最大VerMajor和最大VerMinor为您提供按名称分组的结果。

答案 4 :(得分:0)

我认为您可以使用此代码轻松完成您的要求:

var groupsByName = myItems.GroupBy(x => x.Name.ToLower());

var distinctItems = groupsByName.Select(x => x.ToList()
                                .OrderByDescending(y => y.VM)
                                .ThenByDescending(z => z.Vm).First())
                                .OrderBy(k => k.Name).ToList();