I want to use LINQ to convert this
IEnumerable<int>[] value1ByType = new IEnumerable<int>[3];
value1ByType[0]= new [] { 0};
value1ByType[1]= new [] {10,11};
value1ByType[2]= new [] {20};
var value2ToType = new Dictionary<int,int> {
{100,0},
{101,1},
{102,2},
{103,1}};
to this
var value2ToValue1 = new Dictionary<int,int> {
{100, 0},
{101,10},
{102,20},
{103,11}};
Is there a way to do this with LINQ? Without LINQ I would use multiple IEnumerators, one for each IEnumerable of value1ByType. like this:
// create enumerators
var value1TypeEnumerators = new List<IEnumerator<int>>();
for (int i = 0; i < value1ByType.Length; i++)
{
value1TypeEnumerators.Add(value1ByType[i].GetEnumerator());
value1TypeEnumerators[i].MoveNext();
}
// create wanted dictionary
var value2ToValue1 = new Dictionary<int, int>();
foreach (var item in Value2ToType)
{
int value1=value1TypeEnumerators[item.Value].Current;
value2ToValue1.Add(item.Key, value1);
value1TypeEnumerators[item.Value].MoveNext();
}
Any Idea how to do this in LINQ?
Not pure but you can at least do ...
var enumerators = value1ByType.Select(v => v.GetEnumerator()).ToArray();
var value2ToValue1 = value2ToType
.ToDictionary(x => x.Key, x => { enumerators[x.Value].MoveNext(); return enumerators[x.Value].Current; });
But there are so many ways this could go wrong it begs the question - why was the data in those data-structures anyway? and can you fix that instead? How did you end up with exactly the right number of references in the 2nd data structure to elements in the first?
I'm pretty sure that #Hightechrider's solution is most performant than this one, but if you really like the syntax sugar way, you can do it like this:
public IDictionary<int, int> MergeSequences(IEnumerable<int>[] value1ByType, Dictionary<int, int> value2ToType)
{
int pos = 0;
var value1ByTypePos = from byType in value1ByType
select new { Pos = pos++, Enumerator = byType.GetEnumerator() };
return (from byType in value1ByTypePos
join toType in value2ToType
on byType.Pos equals toType.Value
select new { toType.Key, Value = byType.Enumerator.GetNext() })
.ToDictionary(pair => pair.Key, pair => pair.Value);
}
I've added an extension method to the IEnumerator interface like this:
public static T GetNext<T>(this IEnumerator<T> enumerator)
{
if (!enumerator.MoveNext())
throw new InvalidOperationException();
return enumerator.Current;
}
Now you have to be aware that any of this solutions can give you slightly different results, depending on how elements in the dictionary are enumerated. For example, another valid result to this code is:
var value2ToValue1 = new Dictionary<int,int> {
{100, 0},
{103, 10},
{102, 20},
{101, 11}};
Notice that now 101 is paired with 11 and 103 is paired with 10. If this is a problem, then you should use a SortedDictionary<int, int> when defining value2ToType variable.
What you can do for sure is replace the first part with the following:
var value1TypeEnumerators = value1ByType.ToList();
instead of using an enumerator.
If I do not care about performance I could also write:
var value2Ordered = Value2ToType.OrderBy(x => x.Value).Select(x=>x.Key);
var value1Ordered = from item in value1ByType from subitem in item select subitem;
var value2ToValue1 = value2Ordered.Zip(value1Ordered, (x, y) => new { Key = x, Value = y })
.ToDictionary(item => item.Key, item => item.Value);
I used the zip method from a stackoverflow community wiki. I didn't test this with the c#4.0 zip method
Related
Currently, I have implemented two lists with a double for loop to find matches between the two lists so I can join on them.
I have a list A which contains an ID and some other columns. I have a list B which contains an ID and some other columns. I have currently implemented a for loop within a for loop in order to make the comparisons for all the IDs so that I can find the ones that match and then return the joined results. I know want to understand how to implement a dictionary in this case as that will be more efficient to fix this problem.
public IEnumerable<Details> GetDetails(string ID)
{
// there are two lists defined up here
for (var item in listA)
{
for (var item2 in listB)
{
if (item.ID == item2.ID)
{
item.Name = item2.name;
}
}
}
return results;
}
Instead of having this double for loop, which is very inefficient. I want to learn how to implement a dictionary to fix this problem.
The dictionary would use the ids as keys (or indexes) so
Dictionary<string, object> myListA = new Dictionary<string, object>();
Dictionary<string, object> myListB = new Dictionary<string, object>();
public object GetDetails(string ID)
{
object a = myListA[ID];
object b = myListB[ID];
// combine them here how you want
// object c = a + b;
return c;
}
How about using linq to achieve your actual requirement? Something like:
public IEnumerable<A> GetDetails(int ID)
{
var listA = new List<A>
{
new A(){ ID = 1, Name = 2 },
new A(){ ID = 3, Name = 4 },
new A(){ ID = 5, Name = 6 },
};
var listB = new List<B>
{
new B(){ X = 1, name = 0 },
new B(){ X = 3, name = 1 }
};
return listA.Join(listB, k => k.ID, k => k.ID, (item, item2) =>
{
item.Name = item2.name;
return item;
}).Where(w => w.ID == ID);
}
If you just want the common IDs in the two lists, you can achieve that like this:
var commonIds = listA.Select(o => o.ID).Intersect(listB.Select(o => o.ID));
class MyClass
{
string identifier;
}
I have two lists of identical count
List<MyClass> myClassList;
List<string> identifierList;
I would like to know what is the best way of assigning identifier in the myClassList enumerating over identifierList?
I wrote this, but looks too long(and inefficient?). There must be a better way of doing this?
identifierList.Select((value,index)=>new {value, index}).ToList().ForEach(x=> myClassList[x.index].identifier = x.value);
Yes, you're approach is inefficient(you're creating a throwaway list) and not very readable and also throws an exception if both lists have a different size.
You're looking for the Enumerable.Zip extension method which joins by index:
var zipped = myClassList.Zip(identifierList, (c, s) => new { class = c, string = s});
foreach(var x in zipped)
x.class.identifier = x.string;
You can use Zip:
myClassList.Zip(identifierList, (klass, id) =>
{
klass.identifier = id;
return klass
});
Note that this will give you a mutating Linq expression.
However, I suspect this is probably clearer:
for(int i = 0; i < myClassList.Count; i++)
{
myClassList[i].identifier = identifierList[i];
}
It may not be as "hip" as using Linq, but it's easier to read and understand what's going on!
Well, how about simple query like this.
myClassList.Select((e, i) => { e.identifier = identifierList[i]; return e; }).ToList();
We need this .ToList() to execute the query, otherwise it'll just do nothing.
Example :
List<string> identifierList = new List<string>()
{
"abc", "def", "ghi"
};
List<MyClass> myClassList = new List<MyClass>()
{
new MyClass(), new MyClass(), new MyClass(),
};
myClassList.Select((e, i) => { e.Id = identifierList[i]; return e; }).ToList();
foreach (var item in myClassList)
Console.Write(item.Id + " ");
Output : abc def ghi
In case your collections are of different length you can use :
myClassList.Select((e, i) => { e.Id = i < identifierList.Count? identifierList[i] : e.Id; return e; }).ToList();
I have these two dictionaries:
Dictionary<char, double> analyzed_symbols = new Dictionary<char, double>();
Dictionary<char, double> decode_symbols = new Dictionary<char, double>();
I need to create another dictionary that should have their keys as key and value, like this:
Dictionary<char, char> replace_symbols = new Dictionary<char, char>();
The condition to "join" them is that difference between values should be minimal, like this:
Math.Min(Math.Abs(analyzed_symbols[key] - decode_symbols[key]))
I guess I should use LINQ for this purpose but can't figure out how to write query properly.
Data Sample:
analyzed_symbols = [a, 173], [b, 1522], [z, 99]
decode_symbols = [в, 100], [д, 185], [e, 1622]
For these dicts output data should look like this:
replace_symbols = [z, в], [b, е], [a, д]
I've found question that is pretty close to what I need, but not exactly. Snowy asks there about one close value, but I need to do the same thing for two dictionaries.
This is my take on it:
var analyzed_symbols = new Dictionary<char, double>(){ {'a', 173}, {'b', 1522}, {'z', 99} };
var decode_symbols = new Dictionary<char, double>(){ {'в', 100}, {'д', 185}, {'e', 1622} };
var q = from a in analyzed_symbols
from d in decode_symbols
let tmp = new { A = a.Key, D = d.Key, Value = Math.Abs(a.Value - d.Value) }
group tmp by tmp.A into g
select new
{
Key = g.Key,
Value = g.OrderBy (x => x.Value).Select (x => x.D).First()
};
var replace_symbols = q.ToDictionary (x => x.Key, x => x.Value);
Okay, I'll try. I divided into several queries, because it's more readable that way.
//sorting values of the dictionaries to easily get closest
var analyzedSortedValues = analyzed_symbols.Values.OrderBy(k => k);
var decodeSortedValues = decode_symbols.Values.OrderBy(k => k);
//creating pairs of the closest values. Here I use iterator index i to skip
//some values that have been used already (is it correct?)
var t = analyzedSortedValues.Select((k, i) => new { a = k, d = decodeSortedValues.Skip(i).Any() ? decodeSortedValues.Skip(i).First() : -1 });
//printing results by getting appropriate keys from corresponding dictionaries
foreach (var item in t)
{
Console.WriteLine("[{0}, {1}]", analyzed_symbols.FirstOrDefault(kvp => kvp.Value == item.a).Key, decode_symbols.FirstOrDefault(kvp => kvp.Value == item.d).Key);
}
I am not exactly sure how to do it via LINQ but here is the longhand version of what you want to do.
private static Dictionary<char, char> BuildReplacementDictionary(Dictionary<char, double> analyzedSymbols,
Dictionary<char, double> decodeSymbols)
{
Dictionary<char, char> replaceSymbols = new Dictionary<char, char>(analyzedSymbols.Count);
foreach (KeyValuePair<char, double> analyzedKvp in analyzedSymbols)
{
double bestMatchValue = double.MaxValue;
foreach (KeyValuePair<char, double> decodeKvp in decodeSymbols)
{
var testValue = Math.Abs(analyzedKvp.Value - decodeKvp.Value);
if (testValue <= bestMatchValue)
{
bestMatchValue = testValue;
replaceSymbols[analyzedKvp.Key] = decodeKvp.Key;
}
}
}
return replaceSymbols;
}
What it does is it goes through each element of the analyzed dictionary, test every element of the decoded dictionary, and if that match is the same or better than the previous match it found it will use the new value from the decoded dictionary.
I have a dictionary: Dictionary<int,int>. I want to get new dictionary where keys of original dictionary represent as List<int>. This is what I mean:
var prices = new Dictionary<int,int>();
The prices contain the following data:
1 100
2 200
3 100
4 300
I want to get the IList<Dictionary<int,List<int>>>:
int List<int>
100 1,3
200 2
300 4
How can I do this?
var prices = new Dictionary<int, int>();
prices.Add(1, 100);
prices.Add(2, 200);
prices.Add(3, 100);
prices.Add(4, 300);
Dictionary<int,List<int>> test =
prices.GroupBy(r=> r.Value)
.ToDictionary(t=> t.Key, t=> t.Select(r=> r.Key).ToList());
You can use GroupBy.
Dictionary<int,List<int>> groups =
prices.GroupBy(x => x.Value)
.ToDictionary(x => x.Key, x => x.Select(i => i.Key).ToList());
Here is my reply. When the dictionaries get large, you will likely find the GroupBy() extension methods less efficient than you would like, as they provide many guarantees that you don't need, such as retaining order.
public static class DictionaryExtensions
{
public static IDictionary<TValue,List<TKey>> Reverse<TKey,TValue>(this IDictionary<TKey,TValue> src)
{
var result = new Dictionary<TValue,List<TKey>>();
foreach (var pair in src)
{
List<TKey> keyList;
if (!result.TryGetValue(pair.Value, out keyList))
{
keyList = new List<TKey>();
result[pair.Value] = keyList;
}
keyList.Add(pair.Key);
}
return result;
}
}
And an example to use in LinqPad:
void Main()
{
var prices = new Dictionary<int, int>();
prices.Add(1, 100);
prices.Add(2, 200);
prices.Add(3, 100);
prices.Add(4, 300);
// Dump method is provided by LinqPad.
prices.Reverse().Dump();
}
You can use GroupBy followed by the Func<TSource, TKey>, Func<TSource, TElement> overload of Enumerable.ToDictionary:
var d = prices.GroupBy(x => x.Value).ToDictionary(x => x.Key, x => x.ToList());
You can use Lookup instead.
var prices = new Dictionary<int, int> { {1, 100}, { 2, 200 }, { 3, 100 }, { 4, 300 } };
ILookup<int, int> groups = prices.ToLookup(x => x.Value, y => y.Key);
foreach (var group in groups)
{
foreach (var item in group)
{
Console.WriteLine(item);
}
}
In particular case, when we use the .NET framework 2.0, we can do as follows:
var prices = new Dictionary<int, int>();
prices.Add(1, 100);
prices.Add(2, 200);
prices.Add(3, 100);
prices.Add(4, 300);
Dictionary<int, List<int>> grouping = new Dictionary<int, List<int>>();
var enumerator = prices.GetEnumerator();
while (enumerator.MoveNext())
{
var pair = enumerator.Current;
if (!grouping.ContainsKey(pair.Value))
grouping[pair.Value] = new List<int>();
grouping[pair.Value].Add(pair.Key);
}
I have multiple lists of strings, IList<string>, that I want to consolidate in one list showing distinct string and count for each item (like a dictionary). what is the most efficient way to do this?
LINQ (certainly the most efficient in terms of code to type and maintain; the overall performance will be about the same as any other approach):
if the lists are in separate variables:
var qry = from s in listA.Concat(listB).Concat(listC) // etc
group s by s into tmp
select new { Item = tmp.Key, Count = tmp.Count() };
if the lists are all in a parent list (of lists):
var qry = from list in lists
from s in list
group s by s into tmp
select new { Item = tmp.Key, Count = tmp.Count() };
Then if you really want a list:
var resultList = qry.ToList();
Dictionary<string, int> count = new Dictionary<string, int>();
foreach(IList<int> list in lists)
foreach(int item in list) {
int value;
if (count.TryGetValue(item, out value))
count[item] = value + 1;
else
count[item] = 1;
}
List<List<string>> source = GetLists();
//
Dictionary<string, int> result = source
.SelectMany(sublist => sublist)
.GroupBy(s => s)
.ToDictionary(g => g.Key, g => g.Count())