Как сделать Distinct по длине строки?

256
08 января 2018, 07:43

Есть список

текст;99999
текст фывфы;99999

Я хочу получить уникальные позиции по второй части от разделителя ;. В данном случае это число 99999

Никак не могу найти решение для моей задачи. Написал решение на псевдокоде

var rez = list.DistinctByWhere(x=>x.Split(';')[0].Length.IsMax)

В результате должно остаться в списке только

текст;99999
Answer 1

Как я понял, сравнение происходит не по длине, а по значению второй части расщепленной строки, так?

Если я правильно понял условие, то нужно создать компаратор:

class SplitComparer : IEqualityComparer<string>
{
    public bool Equals(string x, string y)
    {
        var left = x.Split(';')[1];
        var right = y.Split(';')[1];
        return left == right;
    }
    public int GetHashCode(string obj)
    {
        var end = obj.Split(';')[1];
        return end.GetHashCode();
    }
}

Использование:

var result = list.Distinct(new SplitComparer());

Это неэффективно, т. к. сплит происходит два раза, но на скорую руку ничего лучше не придумал.

Конечно, нужно сделать дополнительные проверки в коде или перехват возможных исключений.

Answer 2

Вместо Distinct всегда можно воспользоваться группировкой, а затем взять из каждой группы один (первый) элемент. Это будет выглядеть короче, но, скорее всего, менее эффективно:

string[] lines = { "текст;99999", "текст фывфы;99999" };
var result = lines.GroupBy(line => line.Split(';')[1]).Select(g => g.First());

На самом деле вы не должны работать с таким строками, если одна такая строка представляет собой некий объект, то создайте класс и работайте с полноценными объектами:

class MyData
{
    public string StringProperty { get; set; }
    public int IntProperty { get; set; }
    // Другие свойства ...
    public static MyData Parse(string s)
    {
        var parts = s.Split(';');
        return new MyData
        {
            StringProperty = parts[0],
            IntProperty = int.Parse(parts[1]),
            // Другие свойства ...
        };
    }
}

Теперь просто один раз распарсите свои строки в объекты и работайте с коллекцией объектов:

var data = lines.Select(MyData.Parse).ToList();

если уникальность объектов вашего класса определяется уникальностью одного или нескольких его свойств, то переопределите Equals и GetHashCode в своем классе, это позволит вызывать Distinct вообще без параметров

иначе — создайте классы, реализующие IEqualityComparer<MyData>, наподобие как в соседнем ответе, либо пользуйтесь группировкой, либо подключите библиотеку morelinq из NuGet и воспользуйтесь методом-расширения DistinctBy из ее состава

READ ALSO
Распаковка архива в C#

Распаковка архива в C#

Здравствуйте, мне необходимо распаковать архив updatezip в папку с программой

206
Как лучше организовать поиск по БД?

Как лучше организовать поиск по БД?

ПриветЕсть страница(работаю в WPF) меню, где есть четыре кнопки которые вызывают окно поиска по БД(поиск сотрудников по номеру кабинета, поиск...

204
Обработчик для UserControl

Обработчик для UserControl

Есть 5 шт UserControl'ов, в каждом делаю ( разные названия классов )

174