检查列表中的唯一项(C#)

时间:2009-12-16 15:38:43

标签: c# algorithm

我有一个项目列表。 Item是一个包含两个字段的对象。一个字段的类型为Dictionary<string, List<string>,第二个字段的类型为int。 现在我想检查是否有一个项目,该列表中的两个字段都是唯一的。 使用dict字段我关心关键部分,而不是值,因此值部分可能在项目之间相同。 在该列表中必须是唯一的关键。

如果存在这样的元素,我希望能够在我的列表中获得该元素的位置。

希望很清楚。

澄清 -

这是我的班级

namespace Polstyr
{
class RecordItem
{
    Dictionary<string, List<string>> dict;

    public string MachineNr { get; set; }

    public RecordItem()
    {
        dict = new Dictionary<string, List<string>>();
    }

    public void AddToDict(string value, List<string> list)
    {
        dict.Add(value, list);
    }

    public Dictionary<string, List<string>> GetDictionary
    {
        get
        {
            return dict;
        }
    }
}

}

在我的代码的其他部分,我有名为recordItems的类型List<RecordItem>的列表。

我想检查recordItems列表中的RecordItem对象是否是唯一的 列表基于它的字段。 dict中的键必须是唯一的,MachineNr必须是唯一的。

提前致谢。

3 个答案:

答案 0 :(得分:3)

这是一个我认为可行的LINQ解决方案。

假设:

class A
{
    // your int field
    public int Bar{get; set;} 

    // your dictionary (the value is irrelevant so I've just used bool)
    public Dictionary<string, bool> Foo{ get; set; } 
}

然后:

var nonUniqueFoo = list.SelectMany(a => a.Foo.Keys)
                    .GroupBy( s => s)
                    .Where( g => g.Count() > 1)
                    .Select(g => g.Key);


var nonUniqueBar = list.Select(a => a.Bar)
                    .GroupBy( i => i)
                    .Where( g => g.Count() > 1)
                    .Select(g => g.Key);

var uniqueObjects = list.Where( a=> !nonUniqueBar.Contains(a.Bar) )
                       .Where( a => !nonUniqueFoo.Intersect(a.Foo.Keys).Any() )
              ;

为了完整性,这是我的测试数据:

List<A> list = new List<A>();
list.Add( new A{ Bar=1, Foo = new Dictionary<string, bool>{ {"123", true} } } );
list.Add( new A{ Bar=2, Foo = new Dictionary<string, bool>{ {"456", true}, {"789", true}, {"567", true} } } );
list.Add( new A{ Bar=3, Foo = new Dictionary<string, bool>{ {"AAA", true}, {"456", true}, {"567", true} } } );

答案 1 :(得分:2)

尝试覆盖GetHashCode方法并将IEquatable实现到您的项目

public class RecordItem:IEquatable<RecordItem>
{
...

    public override int GetHashCode()
    {
        int i=0;
        if (dict != null)
        {
            foreach (KeyValuePair<string, List<string>> pair in dict)
                i += pair.Key.GetHashCode();
        }
        i += MachineNr.GetHashCode();
        return i;
    }

    public bool Equals(RecordItem item)
    {

        if (MachineNr != item.MachineNr)
            return false;
        else
        {
            if ((dict != null && item.dict == null) || (dict == null && item.dict != null))
                return false;
            else if (dict != null && item.dict != null)
            {
                foreach (KeyValuePair<string, List<string>> pair in dict)
                {
                    if (!item.dict.ContainsKey(pair.Key))
                        return false;
                }
                return true;
            }
            else return true;
        }
    }
}

GetHashCode将汇总字典和MachineNr中key的所有哈希值。这将确保2个词典具有相同的键 然后,您可以在列表中使用Contains方法。

RecordItem i1 = new RecordItem{ MachineNr="M1"};
i1.AddToDict("1", new List<string>{ "A","B"});
i1.AddToDict("2", null);

RecordItem i2 = new RecordItem{MachineNr = "M1"};
i2.AddToDict("1", null);
i2.AddToDict("2", new List<string> { "A", "B" });

List<RecordItem> lstItem = new List<RecordItem>();
lstItem.Add(i1);
Console.WriteLine(lstItem.Contains(i2));

输出应为真

答案 2 :(得分:1)

您可以创建一个新的查找表来存储您的键和索引位置。迭代您的集合将您的密钥添加到查找表并递增出现次数并附加索引位置。

然后检查查找表中索引位置集合长度等于1的条目。

这就是填充查找表的意思:

class Main
{
    void DoIt()
    {
        Thing[] collection = new [] { new Thing(), new Thing() };
        var lookupTable = new Dictionary<KeyValuePair<int, string>, List<int>>();
        int index = 0;
        foreach (Thing item in collection)
        {
            KeyValuePair<int, string> key = new KeyValuePair<int, string>(item.Bar, item.Foo.Key);
            if (!lookupTable.ContainsKey(key))
                lookupTable.Add(key, new List<int>());
            lookupTable[key].Add(index++);
        }
    }
}

class Thing
{
    public KeyValuePair<string, List<string>> Foo { get; set; }
    public int Bar { get; set; }
}

编辑:现在,我已经看到了您的代码,我认为它会变得非常混乱。我错误地认为您的记录项具有以下属性:

KeyValuePair<string, List<string>>

而不是:

Dictionary<string, List<string>>

我不再了解您需要检索哪个索引位置。你不得不进一步澄清我害怕。具体来说,你说:

  

dict中的键必须是唯一的

但字典有很多键。你的意思是密钥集必须是唯一的吗?