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.
Related
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)}");
}
I have a list of KeyValuePair, of int and a custom object, Function. I also have a list of function Ids. Both lists are sorted alphabetically. I need to match up the function Ids from the 1 list to the function Ids from the other list. So, say the list of KVP looks like:
1, (Function.name = foo, function.Id = 4)
2, (Function.name = bar, function.Id = 7)
And the list of just Ids is:
142
154
I need a dictionary of:
{4, 142}
{7, 154}
So a mash up of the function Ids from both lists.
How can I do this?
Here is what I've tried:
Dictionary<int, int> map = new Dictionary<int, int>();
List<KeyValuePair<int, Function>> sorted = SortFunctions();
IEnumerator sortEnum = sorted.GetEnumerator();
IEnumerator dicEnum = FunctionIds.GetEnumerator();
while ((sortEnum.MoveNext()) && (dicEnum.MoveNext()))
{
//Not sure what to do next? Just map[sortEnum.Next()] = dicEnum.Next()?
}
//Also was trying to use zip.. many many errors
List<string> sortedFuncs = sorted.ToList();
Dictionary<int, int> map2 = functionIds.ToDictionary(x => x, x => sortedFuncs.Value.Id[functionIds.IndexOf(x)]);
You should be able to chain Zip with ToDictionary:
List<KeyValuePair<int, Function>> sorted = SortFunctions();
Dictionary<int, int> map2 =
sorted.Zip(FunctionIds, (s, i) => new {key = s.Value.Id, value = i})
.ToDictionary(x => x.key, x => x.value);
Explanation:
Zip enumerates through the two lists and creates an anonymous type consisting of the Id from the Value of the KeyValuePair in sorted and the integer from FunctionIds. Those values are stored in the key and value property of the anonymous type.
ToDictionary then enumerates that collection and creates a dictionary using the key and the value from the anonymous type (x).
I have 20 dictionaries of <Datetime,double> that are mostly for the same range of dates (e.g. feb 24-2012 through june 4 2012). Some dictionaries have extra days, and some are missing days. I want an array of all the unique dates being used.
Currently I'm iterating through all the keys and adding to a hashset to get a unique set, then converting the hashset to an array. Is there a more efficient way?
For the record I also considered iterating through and using the containsKey function of the dictionary and add to a list, or LINQ. My existing process seems to do the trick.
The code you described is the most efficient you can get.
You can do it with less code (and similar efficency) with LINQ:
dicts.SelectMany(d => d.Keys).Distinct().ToArray();
you can pull all the dictionaries into list that allow "duplicates in keys" and then use the Distinct function:
Dictionary<DateTime, double> dic = new Dictionary<DateTime, double>()
{
{DateTime.Now, 111}
};
Dictionary<DateTime, double> dic2 = new Dictionary<DateTime, double>()
{
{DateTime.Now, 111}
};
var list = dic.ToList();
list.AddRange(dic2.ToList());
var final = list.Distinct().ToDictionary(x => x.Key, x => x.Value);
I found this post while looking for a solution to a slightly different problem but used the accepted answer as the basis for my solution, so I thought someone with the same problem might come down this path too.
I was looking for a way to find a single property in a group of objects that was unique across the property set for each object. I have the property names in dictionaries and I wanted a list of keys that only appear in one dictionary.
Here's my solution, which you should just be able to paste into linqpad to see it working.
void Main()
{
var d = new Dictionary<string, Dictionary<string, string>>
{
{
"First",
new Dictionary<string, string>
{
{"A", "ash"},
{"B", "brett"},
{"R", "ripley"},
{"J", "jones"},
{"D", "dallas"}
}
},
{
"Second",
new Dictionary<string, string>
{
{"A", "ash"},
{"B", "brett"},
{"R", "ripley"},
{"D", "dallas"},
{"K", "kane"}
}
},
{
"Third",
new Dictionary<string, string>
{
{"A", "ash"},
{"B", "brett"},
{"R", "ripley"},
{"D", "dallas"},
{"V", "vasquez"}
}
},
{
"Fourth",
new Dictionary<string, string>
{
{"A", "ash"},
{"B", "brett"},
{"R", "ripley"},
{"D", "dallas"},
{"H", "hicks"}
}
}
};
var u = d.Values.SelectMany(x => x.Keys).Distinct().Where(y => d.Values.SelectMany(z => z.Keys).Count(a => a == y) == 1).ToArray();
foreach (var f in u)
{
Console.WriteLine("{0} => {1}", f, d.Keys.Single(s => ((Dictionary<string, string>)d[s]).ContainsKey(f)));
}
}
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 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);