Проверка наличия уникального элемента в списке (C #) - PullRequest
3 голосов
/ 16 декабря 2009

У меня есть список предметов. Элемент - это объект с двумя полями. Одно поле имеет тип 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;
        }
    }
}

}

В другой части моего кода у меня есть список типа List<RecordItem> с именем recordItems.

Я хотел бы проверить, есть ли в списке recordItems объект RecordItem, который уникален в этом отношении. список на основе его полей. Ключ в dict должен быть уникальным, а MachineNr должен быть уникальным.

Заранее спасибо.

Ответы [ 3 ]

3 голосов
/ 16 декабря 2009

Вот решение 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} } } );
2 голосов
/ 16 декабря 2009

Попробуйте переопределить метод 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. Это гарантирует, что 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));

Вывод должен быть истинным

1 голос
/ 16 декабря 2009

Вы можете создать новую справочную таблицу для хранения ваших ключей и позиций индекса. Повторяйте свою коллекцию, добавляя ключи в таблицу поиска и увеличивая количество вхождений и добавляя позицию индекса.

Затем проверьте таблицу поиска на наличие записей с длинами набора позиций индекса, равными 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 должен быть уникальным

но в словаре много ключей. Вы имеете в виду, что коллекция ключей должна быть уникальной?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...