簡體   English   中英

C# 從列表中刪除重復對象並先增加

[英]C# Remove duplicated objects from list and increase first

我有一個對象列表 => class Example { int quantity; string name; string comment; } class Example { int quantity; string name; string comment; } 我想刪除所有重復class Example { int quantity; string name; string comment; }並通過具有相同namecomment的重復項的數量來增加quantity

例子:

[
    {quantity: 1, name: "Hello", comment: "Hello there"},
    {quantity: 2, name: "Bye", comment: "Good bye"},
    {quantity: 1, name: "Hi", comment: "Hi there"},
    {quantity: 1, name: "Hello", comment: "Hello there"},
    {quantity: 1, name: "Bye", comment: "Good bye"},
]

結果應該是:

[
    {quantity: 2, name: "Hello", comment: "Hello there"},
    {quantity: 3, name: "Bye", comment: "Good bye"},
    {quantity: 1, name: "Hi", comment: "Hi there"}
]

我想刪除所有重復項

您尚未定義兩個示例對象何時“重復”。 我猜,你的意思是說,如果兩個 Examples 對象的屬性NameComment具有相同的值,那么它們就是重復的。

通常,您可以使用Enumerable.GroupBy的重載之一來查找重復項。 使用帶有參數resultSelector的重載來准確定義您想要的結果。

IEnumerable<Example> examples = ...
var result = examples.GroupBy(

    // key: Name-Comment
    example => new
    {
        Name = example.Name,
        Comment = example.Comment,
    }

    // parameter resultSelector: for every Name/Comment combination and all
    // Examples with this Name/Comment combination make one new example:
    (nameCommentCombination, examplesWithThisNameCommentCombination) => new Example
    {
         Name = nameCommentCombination.Name,
         Comment = nameCommentCombination.Comment,

         // Quantity is the sum of all Quantities of all Examples with this
         // Name/Comment combination
         Quantity = examplesWithThisNameCommentCombination
                    .Select(example => example.Quantity)
                    .Sum(),
    });

這僅在您想要精確的字符串相等時才有效。 “你好”和“你好”是否相等? 那么“Déjà vu”和“Deja vu”呢? 您想要名稱和評論不區分大小寫嗎? 那么變音字符呢?

如果您想要的不僅僅是簡單的字符串相等,請考慮創建一個 ExampleComparer class。

class ExampleComparer : EqualityComparer<Example>
{
    ... // TODO: implement
}

用法是:

IEnumerable<Example> examples = ...
IEqualityComparer<Example> comparer = ...

var result = examples.GroupBy(example => example,  // key

    // resultSelector:
    (key, examplesWithThisKey) => new Example
    {
         Name = key.Name,
         Comment = key.Comment,
         Quantity = examplesWithThiskey.Sum(example => example.Quantity),
    },

    comparer);

實現 ExampleComparer

class ExampleComparer : EqualityComparer<Example>
{
    public static IEqualityComparer<Example> ByNameComment {get;} = new ExampleComparer;

    private static IEqualityComparer<string> NameComparer => StringComparer.CurrentCultureIgnoreCase;
    private static IEqualityComparer<string> CommentComparer => StringComparer.CurrentCultureIgnoreCase;

我選擇了兩個單獨的字符串比較器,所以如果稍后您決定不同的比較,例如名稱必須完全匹配,那么您只需在此處更改它。

public override bool Equals (Example x, Example y)
{
    // almost every Equals method starts with the following three lines
    if (x == null) return y == null;                // true if both null
    if (y == null) return false;                    // false, because x not null
    if (Object.ReferenceEquals(x, y)) return true;  // same object

    // return true if both examples are considered equal:
    return NameComparer.Equals(x.Name, y.Name)
        && CommentComparer.Equals(x.Comment, y.Comment);
}

public override int GetHashCode(Example x)
{
     if (x == null) return 5447125;       // just a number

     return NameComparer.GetHashCode(x.Name)
          ^ CommentComparer.GetHashCode(x.Comment);
}

注意:如果名稱或評論是 null 或為空,這也將起作用!

我使用了operator ^ (XOR) ,因為如果只有兩個字段需要考慮,這會給出一個相當好的 hash 。 如果您認為絕大多數示例具有唯一名稱,請考慮僅檢查屬性名稱:

return NameComparer.GetHashCode(x.Name);

因為方法Equals使用 NameComparer 和 CommentComparer 來檢查相等性,所以請確保使用相同的比較器來計算 HashCode。

這是一個簡單的解決方案,它可以在 List tata 中為您提供答案,但如果您願意,您可以執行.ToArray()。

    public class Example 
    { 
        public int quantity; 
        public string name; 
        public string comment; 
    }

    Example[] toto = new Example[]
    {
        new Example
        {
            quantity = 1,
            name = "Hello",
            comment = "Hello there"
        },
        new Example
        {
            quantity = 2,
            name = "Bye",
            comment = "Good bye"
        },
        new Example
        {
            quantity = 1,
            name = "Hi",
            comment = "Hi there"
        },
        new Example
        {
            quantity = 1,
            name = "Hello",
            comment = "Hello there"
        },
         new Example
        {
            quantity = 1,
            name = "Bye",
            comment = "Good bye"
        }
    };

    List<Example> tata = new List<Example>();
    foreach (Example exa in toto)
    {
        bool found = false;
        foreach (Example exb in tata)
        {
            if (exb.name == exa.name && exb.comment == exa.comment)
            {
                exb.quantity += exa.quantity;
                found = true;
                break;
            }
        }
        if (!found)
        {
            tata.Add(exa);
        }
    }

LINQ 是一個很好的練習!

這是我要做的:

Example[] before = new Example[]
{
    new Example { Quantity = 1, Name = "Hello", Comment = "Hello there" },
    new Example { Quantity = 2, Name = "Bye", Comment = "Good bye" },
    new Example { Quantity = 1, Name = "Hi", Comment = "Hi there" },
    new Example { Quantity = 1, Name = "Hello", Comment = "Hello there" },
    new Example { Quantity = 1, Name = "Bye", Comment = "Good bye" },
};

Example[] after =
    before
        .GroupBy(x => new { x.Name, x.Comment }, x => x.Quantity)
        .Select(x => new Example { Quantity = x.Sum(), Name = x.Key.Name, Comment = x.Key.Comment })
        .ToArray();

這給出了:

后

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM