Find value in Dictionary<int,List<int>> - c#

I have a dictionary with int key and List value
I would like to find out if the key or values contains a specific integer and get the related key for it.
Example:
Dictionary<int, List<int>> removableStuff = new Dictionary<int, List<int>>();
removableStuff.Add(1, new List<int> {1});
removableStuff.Add(3, new List<int> {9,33,35});
removableStuff.Add(2, new List<int> {1,65,32,3});
I would like to find the number 3.
Since the number 3 can be found as key and value, the output would be: 3, 2.

This should yield the desired result:
var num = 3;
var keys = removableStuff.Where(i => i.Key.Equals(num) || i.Value.Any(num.Equals))
.Select(i => i.Key);
You can optionally call .ToList() after the .Select(), if you don't want to deal with an Enumerable.
The i.Value.Any(num.Equals) can also be simplified to i.Value.Contains(num), but when I use Linq I like to use Any for that sort of stuff too. (Just personal preference)
Nonetheless this is very basic Linq and I'm sure you would've found your answer prior to asking, if you would've looked.

A similar method to Tobias' answer is to use Contains instead of Any(Equals):
Dictionary<int, List<int>> removableStuff = new Dictionary<int, List<int>>
{
{1, new List<int> {1}},
{3, new List<int> {9, 33, 35}},
{2, new List<int> {1, 65, 32, 3}}
};
int find = 3;
var matches = removableStuff.Where(item => item.Key == find || item.Value.Contains(find));
foreach (var match in matches)
{
Console.WriteLine($"{match.Key}: {string.Join(", ", match.Value)}");
}

Related

How do I use LINQ to compare one value from its previous value?

Heres the following code:
Dictionary<int, List<int>> dic = new Dictionary<int, List<int>>();
dic.Add(1, new List<int>());
dic[1].Add(10);
dic[1].Add(6);
dic.Add(2, new List<int>());
dic[2].Add(9);
dic[2].Add(7);
dic[2].Add(7);
dic.Add(3, new List<int>());
dic[3].Add(9);
dic[3].Add(10);
dic[3].Add(9);
dic.Add(4, new List<int>());
dic[4].Add(6);
// Will give KVPs of Key 1 and 4
var under7 = dic.Where(T => T.Value.Any(Y => Y < 7));
So I've easily found which KVPs contain a value of under 7.
My question is how can I iterate over the dictionary to find out KVPs which have duplicate values with a key following another key (already in order).
As in this should be picked up:
dic.Add(2, new List<int>());
dic[2].Add(9);
dic[2].Add(7); // MATCH
dic[2].Add(7); // MATCH
But not this:
dic.Add(3, new List<int>());
dic[3].Add(9); // NOT MATCH
dic[3].Add(10);
dic[3].Add(9); // NOT MATCH
Is there any way to do this using LINQ?
Tried to give it a go, using something like below but obviously it doesn't work that way.
// Should give KVP of Key 2 but not 3
var dupVals = dic.Where(T => T.Value.Aggregate( (i1, i2) => i1 == i2));
var dupVals = dic.Where(T => T.Value.Any( (i1,i2) => i1 == i2 ));
EDIT:
So Sergey had the answer:
var result = dic.Where(kvp =>
kvp.Value.Skip(1).Zip(kvp.Value, (x, y) => x == y).Any(b => b));
But how exactly does this work?
You can check whether list has two consecutive duplicates with
list.Skip(1).Zip(list, (x,y) => x == y).Any(b => b)
Do this for each value in dictionary:
// yep, you can use this pretty initializer
var dic = new Dictionary<int, List<int>> {
{ 1, new List<int> { 10, 6 }},
{ 2, new List<int> { 9, 7, 7 }},
{ 3, new List<int> { 9, 10, 9 }},
{ 4, new List<int> { 6 }}
};
var result = dic.Where(kvp =>
kvp.Value.Skip(1).Zip(kvp.Value, (x, y) => x == y).Any(b => b));
Explanation: Enumerable.Zip extension applies specified function (x,y) => x == y to corresponding elements of two sequences. These two sequences is list, and same list shifted one item forward. I.e. you are applying function to index and index + 1 items of same list. This function produces result of items comparison. So, Zip will return sequence of true and false depending on equality of consecutive items. If there is any true in result, then you have two consecutive duplicates.
Step by step sample: Consider following list 9, 10, 9, 7, 7. If you'll skip first item in this list, you will get sequence 10, 9, 7, 7. Zipping of these two sequences will produce following item pairs (you should pic corresponding items - first and first, second and second, etc): (10, 9), (9, 10), (7,9), (7,7). Next step is applying (x,y) => x == y function to each pair. Result will be false, false, false, true. As you can see, last pair (fourth item from first sequence and fourth item from second sequence) has equal items, thus it produces true. And last thing is checking whether any of pairs produced true.

Compare Keys in Two Dictionaries

I'm trying to compare two dictionaries, the program is written in C# Visual Studio 2010.
Dictionary<int, string> members1 = new Dictionaries<int, string>{
{1, "adam"},
{2, "bob"},
{3, "cameron"}
}
Dictionary<int, string> members2 = new Dictionaries<int, string>{
{1, "adam"},
{2, "bill"},
{4, "dave"}
}
I would like to find the same id (key), and it doesn't matter if the name (value) is the same or not.
I've been searching and found Intersect and Except, but I don't think it work quite the way I wanted it.
With the example above, if I call an Intersect function, I want it to return List<int>{1, 2}.
If I call something like members1.Except(members2), I want it to return
Dictionary<int, string> intersectMembers{
{1, "adam"},
}
A solution I thought of doing is to write 2 for-loops and using dictionary.Contains(key) to get the result I want.
Is there a more straight forward way of doing this?
Thanks
If you want a "Common Dictionary" returned I believe you could do it this way:
var intersectMembers = members1.Keys.Intersect(members2.Keys)
.ToDictionary(t => t, t => members1[t]);
or, alternatively:
var intersectMembers = members1.Where(x => members2.ContainsKey(x.Key))
.ToDictionary(x => x.Key, x => x.Value);
However, if you want a "Common List" returned then Sergey is right and you can implement his answer.
var commonKeys = members1.Keys.Intersect(members2.Keys); // { 1, 2 }
That will return IEnumerable<int> but you can call ToList() if you want list.

Using C# lambdas to combine List<int> and int

I have the following list of Pair objects:
var listOfPairs = new List<Pair<int, List<int>>>() {
new Pair<int, List<int>>(30, new List<int>() {3, 6, 9}),
new Pair<int, List<int>>(40, new List<int>() {4, 8, 12})
};
I would like to end up with the following list of list-of-integers:
listOfPairs[0] = {30, 3, 6, 9};
listOfPairs[1] = {40, 4, 8, 12};
I've tried a lot of fiddling that looks like this, but to no avail:
var flattenedListOfPairs = listOfPairs.Select(pair => new List<int>(pair.First).AddRange(pair.Second));
I assume that what I'm trying to do is possible, and I'm just missing something.
Sounds like you might want something like:
var flattened = listOfPairs.Select(pair => new[] { pair.First }.Concat(pair.Second)
.ToList())
.ToList();
Or:
var flattened = listOfPairs.Select(pair => Enumerable.Repeat(pair.First, 1)
.Concat(pair.Second)
.ToList())
.ToList();
Or using MoreLINQ
var flattened = listOfPairs.Select(pair => pair.Second.Prepend(pair.First)
.ToList())
.ToList();
This gives you a list of lists, in the form you specified:
listOfPairs.Select(p => new []{ p.First }.Concat(p.Second).ToList()).ToList()
Other answers already covered how to do this, so I won't repeat that here. This answer is to explain why your existing code wasn't working. You expected to pass an int to the List constructor and have it initialize the List with that int. That's not how the constructor works. The List constructor uses the int argument to set up the initial size of the list, rather than set the value of any items.
Try this:
var flattenedListOfPairs = listOfPairs.Select(pair =>
{
var list = new List<int>(pair.First);
list.AddRange(pair.Second));
return list;
}.ToList();

What's the C# equivalence of Python's min/max

What's C#'s equivalence of the following Python's min/max code:
pairs = [ (2,"dog"), (1, "cat"), (3, "dragon"), (1, "tiger") ]
# Returns the PAIR (not the number) that minimizes on pair[0]
min_pair = min(pairs, key=lambda pair:pair[0])
# this will return (1, 'cat'), NOT 1
It seems that C#'s Enumerable.Min is very close. But according to its MSDN doc, it always returns the minimizing VALUE (not the original object). Am I missing anything?
EDIT
Please note - I'm not inclined to achieve this by sorting first, since sorting (O(nlogn)) is computationally heavier than finding the minimum (O(n)).
Please also note - Dictionary is not a desired approach either. It cannot handle cases where there are duplicate keys - (1, "cat") and (1, "tiger").
More importantly, dictionary cannot handle cases where the items to be processed is a complex class. E.g., finding minimum over a list of animal objects, using age as the key:
class Animal
{
public string name;
public int age;
}
The BCL doesn't have a MinBy function, but it's easy to write one yourself.
public static T MinBy<T, C>(this IEnumerable<T> items, Func<T, C> projection) where C : IComparable<C> {
return items.Aggregate((acc, e) => projection(acc).CompareTo(projection(e)) <= 0 ? acc : e);
}
You may choose to write a more complex MinBy than me, in order to avoid re-evaluating the projection. In any case, once you have your MinBy function you can easily solve the problem:
var pairs = new[] {Tuple.Create(2,"dog"), Tuple.Create(1, "cat"), Tuple.Create(3, "dragon"), Tuple.Create(1, "tiger")};
var min_pair = pairs.MinBy(e => e.Item1);
Use
Dictionary<int, string> pairs = new Dictionary<int, string>()
{ {2,"dog"}, {1, "cat"}, {3, "dragon"} };
var min = pairs.OrderBy(x => x.Key).FirstOrDefault();
OR
int min = pairs.Keys.Min();
Dictionary<int, string> result
= new Dictionary<int, string>() { {min, pairs[min]} };
I would use
var min = pairs.OrderBy(x => x.FirstValue).FirstOrDefault();
and while I agree that sorting is heavier than finding the minimum value please note that this is not sorting the entire set. It is finding the first (or default) item in an ordered enumeration over the set - which is iterated lazily.
If you had
var min = pairs.OrderBy(x => x.FirstValue).ToList().FirstOrDefault();
then I'd agree - you are sorting your pairs and then taking the first. But LINQ is smarter than that, and you will not be sorting the set. You'll be taking the first from a potentially ordered but as yet unexecuted collection.
In addition to your point about Dictionary being unable to use a complex collection - say a list of Animal - how would you sort by an Animal? You can never sort by a complex object. You instead need to use the age of the animal as the key. Dictionary can do this very easily - in fact, the key of a Dictionary would never be the same as the value of a Dictionary, else what would be the point?
var animals = new List<Animal>();
// get some animals...
var animalictionary = animals.ToDictionary(a => a.Age);
// assuming the animals have distinct ages, else
var animalLookup = animals.ToLookup(a => a.Age);
foreach (var animalGroup in animalLookup)
{
var age = animalGroup.Key;
Console.WriteLine("All these animals are " + age);
foreach (Animal animal in animalGroup)
{
Console.WriteLine(animal.name);
}
}
EDIT
var minage = collection.Min( x => x.Age ); //for maxage replace Min by Max
var minAgeAnimals = collection.where(x=> x.age == minage);
foreach(Animal animal in minAgeAnimals )
Console.Writeline ( animal.Age.ToString() + " : " + animal.Name);
Prev. Answered before edit of question
Make use of dictonary object in C# and than do something like this does the same thing you want
int minimumKey = touchDictionary.Keys.Min();
string value = "";
touchDictionary.TryGetValue(minimumKey, out value))
Console.Writeline ( "min key pair is:-" + minimumKey.ToString() + " : " + value);
or
With the help of the linq its become to easy for you
var dictionary = new Dictionary<int, string>
{{1, "one"}, {2, "two"}, {3, "three"}, {4, "four"} };
var maxKey = dictionary.Max(x => x.Key);
var minkey = dictionary.Min(x => x.Key);

Intersection of multiple lists with IEnumerable.Intersect()

I have a list of lists which I want to find the intersection for like this:
var list1 = new List<int>() { 1, 2, 3 };
var list2 = new List<int>() { 2, 3, 4 };
var list3 = new List<int>() { 3, 4, 5 };
var listOfLists = new List<List<int>>() { list1, list2, list3 };
// expected intersection is List<int>() { 3 };
Is there some way to do this with IEnumerable.Intersect()?
EDIT:
I should have been more clear on this: I really have a list of lists, I don't know how many there will be, the three lists above was just an example, what I have is actually an IEnumerable<IEnumerable<SomeClass>>
SOLUTION
Thanks for all great answers. It turned out there were four options for solving this: List+aggregate (#Marcel Gosselin), List+foreach (#JaredPar, #Gabe Moothart), HashSet+aggregate (#jesperll) and HashSet+foreach (#Tony the Pony). I did some performance testing on these solutions (varying number of lists, number of elements in each list and random number max size.
It turns out that for most situations the HashSet performs better than the List (except with large lists and small random number size, because of the nature of HashSet I guess.)
I couldn't find any real difference between the foreach method and the aggregate method (the foreach method performs slightly better.)
To me, the aggregate method is really appealing (and I'm going with that as the accepted answer) but I wouldn't say it's the most readable solution.. Thanks again all!
How about:
var intersection = listOfLists
.Skip(1)
.Aggregate(
new HashSet<T>(listOfLists.First()),
(h, e) => { h.IntersectWith(e); return h; }
);
That way it's optimized by using the same HashSet throughout and still in a single statement. Just make sure that the listOfLists always contains at least one list.
You can indeed use Intersect twice. However, I believe this will be more efficient:
HashSet<int> hashSet = new HashSet<int>(list1);
hashSet.IntersectWith(list2);
hashSet.IntersectWith(list3);
List<int> intersection = hashSet.ToList();
Not an issue with small sets of course, but if you have a lot of large sets it could be significant.
Basically Enumerable.Intersect needs to create a set on each call - if you know that you're going to be doing more set operations, you might as well keep that set around.
As ever, keep a close eye on performance vs readability - the method chaining of calling Intersect twice is very appealing.
EDIT: For the updated question:
public List<T> IntersectAll<T>(IEnumerable<IEnumerable<T>> lists)
{
HashSet<T> hashSet = null;
foreach (var list in lists)
{
if (hashSet == null)
{
hashSet = new HashSet<T>(list);
}
else
{
hashSet.IntersectWith(list);
}
}
return hashSet == null ? new List<T>() : hashSet.ToList();
}
Or if you know it won't be empty, and that Skip will be relatively cheap:
public List<T> IntersectAll<T>(IEnumerable<IEnumerable<T>> lists)
{
HashSet<T> hashSet = new HashSet<T>(lists.First());
foreach (var list in lists.Skip(1))
{
hashSet.IntersectWith(list);
}
return hashSet.ToList();
}
Try this, it works but I'd really like to get rid of the .ToList() in the aggregate.
var list1 = new List<int>() { 1, 2, 3 };
var list2 = new List<int>() { 2, 3, 4 };
var list3 = new List<int>() { 3, 4, 5 };
var listOfLists = new List<List<int>>() { list1, list2, list3 };
var intersection = listOfLists.Aggregate((previousList, nextList) => previousList.Intersect(nextList).ToList());
Update:
Following comment from #pomber, it is possible to get rid of the ToList() inside the Aggregate call and move it outside to execute it only once. I did not test for performance whether previous code is faster than the new one. The change needed is to specify the generic type parameter of the Aggregate method on the last line like below:
var intersection = listOfLists.Aggregate<IEnumerable<int>>(
(previousList, nextList) => previousList.Intersect(nextList)
).ToList();
You could do the following
var result = list1.Intersect(list2).Intersect(list3).ToList();
This is my version of the solution with an extension method that I called IntersectMany.
public static IEnumerable<TResult> IntersectMany<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TResult>> selector)
{
using (var enumerator = source.GetEnumerator())
{
if(!enumerator.MoveNext())
return new TResult[0];
var ret = selector(enumerator.Current);
while (enumerator.MoveNext())
{
ret = ret.Intersect(selector(enumerator.Current));
}
return ret;
}
}
So the usage would be something like this:
var intersection = (new[] { list1, list2, list3 }).IntersectMany(l => l).ToList();
This is my one-row solution for List of List (ListOfLists) without intersect function:
var intersect = ListOfLists.SelectMany(x=>x).Distinct().Where(w=> ListOfLists.TrueForAll(t=>t.Contains(w))).ToList()
This should work for .net 4 (or later)
After searching the 'net and not really coming up with something I liked (or that worked), I slept on it and came up with this. Mine uses a class (SearchResult) which has an EmployeeId in it and that's the thing I need to be common across lists. I return all records that have an EmployeeId in every list. It's not fancy, but it's simple and easy to understand, just what I like. For small lists (my case) it should perform just fineā€”and anyone can understand it!
private List<SearchResult> GetFinalSearchResults(IEnumerable<IEnumerable<SearchResult>> lists)
{
Dictionary<int, SearchResult> oldList = new Dictionary<int, SearchResult>();
Dictionary<int, SearchResult> newList = new Dictionary<int, SearchResult>();
oldList = lists.First().ToDictionary(x => x.EmployeeId, x => x);
foreach (List<SearchResult> list in lists.Skip(1))
{
foreach (SearchResult emp in list)
{
if (oldList.Keys.Contains(emp.EmployeeId))
{
newList.Add(emp.EmployeeId, emp);
}
}
oldList = new Dictionary<int, SearchResult>(newList);
newList.Clear();
}
return oldList.Values.ToList();
}
Here's an example just using a list of ints, not a class (this was my original implementation).
static List<int> FindCommon(List<List<int>> items)
{
Dictionary<int, int> oldList = new Dictionary<int, int>();
Dictionary<int, int> newList = new Dictionary<int, int>();
oldList = items[0].ToDictionary(x => x, x => x);
foreach (List<int> list in items.Skip(1))
{
foreach (int i in list)
{
if (oldList.Keys.Contains(i))
{
newList.Add(i, i);
}
}
oldList = new Dictionary<int, int>(newList);
newList.Clear();
}
return oldList.Values.ToList();
}
This is a simple solution if your lists are all small. If you have larger lists, it's not as performing as hash set:
public static IEnumerable<T> IntersectMany<T>(this IEnumerable<IEnumerable<T>> input)
{
if (!input.Any())
return new List<T>();
return input.Aggregate(Enumerable.Intersect);
}

Categories