Есть ли шанс получить уникальные записи с помощью Linq (C#)?

Я получил list<list<string>>

в list[x][0] есть записи, из которых я хочу выбрать уникальные записи, поэтому такой записи не будет ни в каком другом list[x][0], когда я выберу ее, я бы хотел, чтобы была выбрана вся строка list[x]. Я не нашел подходящего примера для этого в Linq, пожалуйста, помогите :(

ИЗМЕНИТЬ

Когда Джон Скит просит меня уточнить, я не могу отказать ;-)

list<list<string>>

содержит список строк таблицы. Каждая строка «таблица» содержит несколько ключей list[x][several_items], и я хочу получить уникальные записи из списка->, что означает ПЕРВЫЙ элемент в этой «таблице».

Таким образом:

item[0] = "2","3","1","3"
item[1] = "2","3","4","2"
item[3] = "10","2"
item[4]= "1","2"

-> уникальный означает, что я могу вывести строки item[3] and item[4] как уникальные. потому что первое появление числа/строки важно.

Если есть 2 или более записей/строк (item[x] of which first item (item[x][0]) существует более одного раза в списке, он не уникален.

Первый элемент каждого списка важен для определения уникальности. Может быть, было бы проще, если бы кто-то помог найти способ найти неуникальный -> поэтому из приведенного выше примера списка я получил бы только элемент [0] и элемент [1]


person Skuta    schedule 07.04.2009    source источник
comment
list[x][0] - это, безусловно, одна строка - как это сопоставляется с записями? мне непонятно...   -  person Marc Gravell    schedule 07.04.2009


Ответы (6)


РЕДАКТИРОВАТЬ: я обновил реализацию UniqueBy внизу, чтобы она стала значительно более эффективной, и повторяю исходный код только один раз.

Если я вас правильно понял (вопрос довольно неясен - было бы очень полезно, если бы вы могли привести пример), это то, что вы хотите:

public static IEnumerable<T> OnlyUnique<T>(this IEnumerable<T> source)
{
    // No error checking :)

    HashSet<T> toReturn = new HashSet<T>();
    HashSet<T> seen = new HashSet<T>();

    foreach (T element in source)
    {
        if (seen.Add(element))
        {
            toReturn.Add(element);
        }
        else
        {
            toReturn.Remove(element);
        }
    }
    // yield to get deferred execution
    foreach (T element in toReturn)
    {
        yield return element;
    }
}

РЕДАКТИРОВАТЬ: Хорошо, если вас интересует только первый элемент списка для уникальности, нам нужно его несколько изменить:

public static IEnumerable<TElement> UniqueBy<TElement, TKey>
    (this IEnumerable<TElement> source,
     Func<TElement, TKey> keySelector)
{
    var results = new LinkedList<TElement>();
    // If we've seen a key 0 times, it won't be in here.
    // If we've seen it once, it will be in as a node.
    // If we've seen it more than once, it will be in as null.
    var nodeMap = new Dictionary<TKey, LinkedListNode<TElement>>();

    foreach (TElement element in source)
    {
        TKey key = keySelector(element);
        LinkedListNode<TElement> currentNode;

        if (nodeMap.TryGetValue(key, out currentNode))
        {
            // Seen it before. Remove if non-null
            if (currentNode != null)
            {
                results.Remove(currentNode);
                nodeMap[key] = null;
            }
            // Otherwise no action needed
        }
        else
        {
            LinkedListNode<TElement> node = results.AddLast(element);
            nodeMap[key] = node;
        }
    }
    foreach (TElement element in results)
    {
        yield return element;
    }
}

Вы бы назвали это с помощью:

list.UniqueBy(row => row[0])
person Jon Skeet    schedule 07.04.2009
comment
Я повторил свой вопрос с дополнительной информацией - person Skuta; 07.04.2009
comment
Хм. Боюсь, я все еще не понимаю. Вас интересует только первый элемент каждого списка? Редактирование, чтобы попробовать это... - person Jon Skeet; 07.04.2009
comment
Отредактировано. Надеюсь, это то, что вы хотите сейчас, и эффективно. - person Jon Skeet; 07.04.2009

Что-то вроде этого, наверное?

Теперь я почти уверен, что это сработает для вас, учитывая ваше разъяснение :)

var mylist = new List<List<string>>() {
    new List<string>() { "a", "b", "c" },
    new List<string>() { "a", "d", "f" },
    new List<string>() { "d", "asd" },
    new List<string>() { "e", "asdf", "fgg" }
};
var unique = mylist.Where(t => mylist.Count(s => s[0] == t[0]) == 1);

unique теперь содержит записи "d" и "e" сверху.

person Blorgbeard    schedule 07.04.2009
comment
Я думаю, ты понял. Я проверю его ! :) - person Skuta; 07.04.2009
comment
есть возможность зарезервировать? так что я ищу записи? :D - person Skuta; 07.04.2009
comment
Возможно... Можете ли вы объяснить это немного подробнее? :) - person Blorgbeard; 07.04.2009

Вот код, который вам нужен. У меня отлично работает выбор ТОЛЬКО разных значений.

//distinct select in LINQ to SQL with Northwind
var myquery = from user in northwindDC.Employees
              where user.FirstName != null || user.FirstName != ""
              orderby user.FirstName
              group user by user.FirstName into FN
              select FN.First();
person Huseyin Altindag    schedule 13.10.2010

Вот вам Linq.

List<List<string>> Records = GetRecords();
//
List<List<string> UniqueRecords = Records
  .GroupBy(r => r[0])
  .Where(g => !g.Skip(1).Any())
  .Select(g => g.Single())
  .ToList();
person Amy B    schedule 07.04.2009

Я просто продолжу и добавлю это к драке.

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApplication1 {
    class Program {
        static void Main(string[] args) {
            List<string> xx = new List<string>() { "xx", "yy", "zz" };
            List<string> yy = new List<string>() { "11", "22", "33" };
            List<string> zz = new List<string>() { "aa", "bb", "cc" };
            List<List<string>> x = new List<List<string>>() { xx, yy, zz, xx, yy, zz, xx, yy };
            foreach(List<string> list in x.Distinct()) {
                foreach(string s in list) {
                    Console.WriteLine(s);
                }
            }
        }
    }
}
person Ariel    schedule 07.04.2009
comment
Насколько я знаю linq (на самом деле почти ничего), это неправильно. пожалуйста, проверьте мой пост еще раз :( - person Skuta; 07.04.2009
comment
Что ж, с новой информацией в вашем посте мне кажется, что вы используете неправильную структуру для хранения своих данных. вам может быть лучше с хэш-таблицей или таблицей данных. - person Ariel; 07.04.2009

Вы можете вести список и индекс/словарь:

List<List<string>> values;
Dictionary<string, List<string>> index;

Когда вы добавляете элемент в значения, вы также добавляете список в индекс со строкой в ​​качестве индекса.

values[x].Add(newString);
index[newString] = values[x];

Затем вы можете получить правильный список:

List<string> list = index[searchFor]

Вы теряете некоторую (минимальную) производительность и память при построении индекса, но значительно выигрываете при извлечении данных.

Если строка не уникальна, вы также можете сохранить список> в словарь/index, чтобы разрешить несколько результатов для каждого ключа индекса.

Извините, нет Linq, это выглядит не так уж круто, но у вас есть быстрый поиск, и ИМХО код поиска более понятен.

person GvS    schedule 07.04.2009