Есть ли шанс получить уникальные записи, используя Linq (C #)? - PullRequest
3 голосов
/ 07 апреля 2009

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

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

EDIT

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

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]) существует более одного раза в списке, это не уникально.

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

Ответы [ 6 ]

10 голосов
/ 07 апреля 2009

РЕДАКТИРОВАТЬ: я обновил реализацию 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])
2 голосов
/ 13 октября 2010

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

//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();
2 голосов
/ 07 апреля 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" сверху.

1 голос
/ 07 апреля 2009

Вот тебе Линк.

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();
0 голосов
/ 07 апреля 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);
                }
            }
        }
    }
}
0 голосов
/ 07 апреля 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, это выглядит не так круто, но у вас быстрый поиск, и ИМХО код поиска более ясный.

...