Reputation: 5860
I got a list<list<string>>
in list[x][0]
are records from which I want to choose unique records thus such record wouldn't be in any other list[x][0
], when I choose it, i'd like whole row list[x]
to be chosen. I haven't found the appropriate exapmple for this in Linq, please help :(
EDIT
When Jon Skeet asks me to clarify, I can't deny ;-)
list<list<string>>
contains list of string table . Each of the string "table" contains several keys list[x][several_items]
and I want to get unique records from list-> meaning FIRST item in that "table".
Thus:
item[0] = "2","3","1","3"
item[1] = "2","3","4","2"
item[3] = "10","2"
item[4]= "1","2"
-> unique would mean that I can derive rows item[3] and item[4]
as unique. because first occurence of number/string is important.
If there are 2 or more records/rows (item[x] of which first item (item[x][0])
exists more than once in the list, it's not unique.
First element of each list is important to determine uniqueness. Maybe it'd be easier if someone can help to find a way to find non-unique -> so from the above example the list I'd get only item[0] and item[1]
Upvotes: 3
Views: 10122
Reputation: 21
Here is the code you need. It works perfectly for me to select ONLY distinct values.
//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();
Upvotes: 2
Reputation: 110151
Here's some Linq for you.
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();
Upvotes: 1
Reputation: 52518
You could maintain a list and an index/dictionary:
List<List<string>> values;
Dictionary<string, List<string>> index;
When you add an item to values, you also add the List to the index with the string as index.
values[x].Add(newString);
index[newString] = values[x];
Then you can get the correct list by:
List<string> list = index[searchFor]
You loose some (minimal) performance and memory when building the index, but you gain a lot when retrieving the data.
If the string is not unique, you could also store a List> in the dictionary/index, to allow multiple results per index key.
Sorry no Linq, this doesn't look that cool, but you have a fast lookup, and IMHO the lookup code is more clear.
Upvotes: 0
Reputation: 1501626
EDIT: I've updated the UniqueBy
implementation at the bottom to be significantly more efficient, and only iterate through the source once.
If I've understood you correctly (the question is pretty unclear - it would really help if you could provide an example) this is what you want:
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;
}
}
EDIT: Okay, if you only care about the first element of the list for uniqueness, we need to change it somewhat:
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;
}
}
You'd call it with:
list.UniqueBy(row => row[0])
Upvotes: 10
Reputation: 103507
Something like this, perhaps?
I'm now fairly sure this would work for you, given your clarification :)
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
now contains the "d" and "e" entries from above.
Upvotes: 2
Reputation: 872
I'll just go ahead and add this one to the fray.
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);
}
}
}
}
}
Upvotes: 0