How to convert List<String> to Dictionary<int,String> - c#

I have List<String>, i need to convert it to Dictionary<int,String> with auto generation of Key, is any shortest way to accomplish that? I have tried:
var dictionary = new Dictionary<int, String>();
int index = 0;
list.ForEach(x=>{
definitions.Add(index, x);
index++;
});
but i think it is dirty way.

var dict = list.Select((s, i) => new { s, i }).ToDictionary(x => x.i, x => x.s);

I find this to be the neatest
int index = 0;
var dictionary = myList.ToDictionary(item => index++);

In my opinion, what you have is more readable than the Linq way (and as a bonus, it happens to be more efficient):
foreach(var item in list)
dictionary[index++] = item;

Use:
var dict = list.Select((x, i) => new {x, i})
.ToDictionary(a => a.i, a => a.x);

Related

Search in dictionary of dictionaries

I have a dictionary defined as seen here:
Dictionary<int, Dictionary<string, object>> dict = new Dictionary<..>();
And a sample code for adding data:
dict.Add (X, new Dictionary<string, object> ());
dict [X].Add ("Car", CarObject);
dict [X].Add ("Seller", SellerObject);
dict [X].Add ("Key3", Z);
I want to search in the inner dictionary if it contains an object which then contains the following
CarObject.Name = (wildcard)X1(wildcard) of the key "Car" but I just can't seem to get a grasp of how to get into the inner dictionary and then into the object with LINQ in order to search for the value.
This will return all matching KeyValuePair<string, object>.
var query = dict.SelectMany(d => d.Value)
.Where(i => i.Key == "Key1"
&& (
i.Value is CarObject
? ((CarObject)i.Value).Name.Contains("X1")
: false
));
Try the following:
var results = dict[X].Where(x => (x.Value is CarObject) && ((CarObject)x.Value).Name.Contains("X1"));
If you want to get just the value and not the dictionary, and print the values, you can do this:
int X = 0, Z = 1;
dict[X].Add("Key1", CarObject);
dict[X].Add("Key2", SellerObject);
dict[X].Add("Key3", Z);
var results = dict[X].Where(x => (x.Value is CarObject) && ((CarObject)x.Value).Name.Contains("X1")).Select(x => x.Value);
foreach (var str in results)
Console.WriteLine(str);
You can try something like:
dict[X].Where(x => x.Value is CarObject && ((CarObject)x.Value).Name.Contains("X1"));
Or:
dict[X].Values.OfType<CarObject>().Any(x => x.Name.Contains("X1"))

parsing string and create Dictionary

I have the following string pattern: 1:2,2:3.
This is like array in one string:
The first element is: 1:2
The second element is: 2:3
I want to parse it and create a dictionary:
1,2 // 0 element in Dictionary
2,3 // 1 element in Dictionary
This is my code:
Dictionary<int,int> placesTypes = new Dictionary<int, int>();
foreach (var place in places.Split(','))
{
var keyValuePair = place.Split(':');
placesTypes.Add(int.Parse(keyValuePair[0]), int.Parse(keyValuePair[1]));
}
Is there the best way to do this?
Thanks.
You could change it to this:
var d = s.Split(',')
.Select(x => x.Split(':'))
.ToDictionary(x => int.Parse(x[0]), x => int.Parse(x[1]));
Dictionary<int, int> dict = "1:2,2:3".Split(',')
.Select(x => x.Split(':'))
.ToDictionary(x => int.Parse(x[0]),
x => int.Parse(x[1]));
var result = input.Split(new[]{','})
.Select(s => s.Split(new[]{':'}))
.ToDictionary(k => int.Parse(k[0]), v=> int.Parse(v[1]));
Live example: http://rextester.com/GTKO60478
If you're using C# >= 3.5 the ToDictionary LINQ method is the way to go:
var dictionary = places.Split(',')
.Select(place => place.Split(':'))
.ToDictionary(keyValue => int.Parse(keyValue[0]), keyValue => int.Parse(keyValue[1]));
Failing that, the following should suffice:
public static Dictionary<string, string> ToDictionary(string value, char pairSeperator, char valueSeperator)
{
Dictionary<int, int> dictionary = new Dictionary<int, int>();
foreach (string pair in value.Split(pairSeperator))
{
string[] keyValue = pair.Split(valueSeperator);
dictionary.Add(keyValue[0], keyValue[1]);
}
return dictionary;
}
Splitting only once, using MoreLinq.Batch
Dictionary<int, int> dict = places.Split(',', ':').Batch(2).Select(x=>x.ToArray()).ToDictionary(x=>int.Parse(x[0]),x=>int.Parse(x[1]));

zipping/merging two sorted lists

i have two sorted dictionaries both with the type signature
i.e.
SortedDictionary<decimal, long> A
SortedDictionary<decimal, long> B
I want to merge the two lists where the key is the same, thus creating a new list like
SortedDictionary<decimal, KeyValuePair<long,long>>
or
SortedDictionary<decimal, List<long>>
This may not be the best way of approacing the situation but could someone give me a heads up on how to do this or a better way to approach it.
This is what I've got:
SortedDictionary<decimal, List<long>> merged = new SortedDictionary<decimal, List<long>>
(
A.Union(B)
.ToLookup(x => x.Key, x => x.Value)
.ToDictionary(x => x.Key, x => new List<long>(x))
);
EDIT: Above solution selects keys not included in both collections. This should select where keys are same:
SortedDictionary<decimal, List<long>> merged = new SortedDictionary<decimal, List<long>>
(
A.Where(x=>B.ContainsKey(x.Key))
.ToDictionary(x => x.Key, x => new List<long>(){x.Value, B[x.Key]})
);
You can do this simply using LINQ:
var query = from a in A
join b in B
on a.Key equals b.Key
select new {
Key = a.Key,
Value = Tuple.Create(a.Value, b.Value)
};
var merged = new SortedDictionary<decimal, Tuple<long, long>>(
query.ToDictionary(x => x.Key, x => x.Value)
);
I think you should use Tuple<long, long> as your TValue in the merged dictionary.
Another LINQ way of doing this that I think captures the intent better in terms of set operations:
SortedDictionary<decimal, long> a = new SortedDictionary<decimal, long>();
SortedDictionary<decimal, long> b = new SortedDictionary<decimal, long>();
a.Add(0, 10);
a.Add(1, 10);
a.Add(2, 100);
a.Add(100, 1);
b.Add(0, 4);
b.Add(4, 4);
b.Add(2, 10);
var result = a.Union(b)
.GroupBy(x => x.Key)
.ToDictionary(x => x.Key, x => x.Select(y => (long)y.Value).ToList());
Try something like this, it not easy:
Dictionary<decimal, long> dic1 = new Dictionary<decimal, long>{ {3,23}, {2,3}, {5,4}, {6,8}};
Dictionary<decimal, long> dic2 = new Dictionary<decimal, long>{ {3,2}, {2,5}, {5,14}, {12,2}};
//recover shared keys (the keys that are present in both dictionaries)
var sharedKeys = dic1.Select(dic => dic.Key).Intersect(dic2.Select(d2=>d2.Key));
sharedKeys.Dump();
//add to the fìnal dictionary
var final = new Dictionary<decimal, List<long>>();
foreach(var shk in sharedKeys) {
if(!final.ContainsKey(shk))
final[shk] = new List<long>();
final[shk].Add(dic1[shk]);
final[shk].Add(dic2[shk]);
}
**EDIT**
//Skip below part if you need only keys present on both dictionaries.
///-----------------------------------------------------------------
//get unique keys present in Dic1 and add
var nonsharedkeys1 = dic1.Select(d=>d.Key).Where(k=>!sharedKeys.Contains(k));
foreach(var nshk in nonsharedkeys1) {
final[nshk] = new List<long>();
final[nshk].Add(dic1[nshk]);
}
//get unique keys present in Dic2 and add
var nonsharedkeys2 = dic2.Select(d=>d.Key).Where(k=>!sharedKeys.Contains(k));
foreach(var nshk in nonsharedkeys2) {
final[nshk] = new List<long>();
final[nshk].Add(dic2[nshk]);
}
Should work for you.
You could "abuse" Concat and Aggregate like this:
var A = new SortedDictionary<decimal,long>();
var B = new SortedDictionary<decimal,long>();
A.Add(1, 11);
A.Add(2, 22);
A.Add(3, 33);
B.Add(2, 222);
B.Add(3, 333);
B.Add(4, 444);
var C = A.Concat(B).Aggregate(
new SortedDictionary<decimal, List<long>>(),
(result, pair) => {
List<long> val;
if (result.TryGetValue(pair.Key, out val))
val.Add(pair.Value);
else
result.Add(pair.Key, new[] { pair.Value }.ToList());
return result;
}
);
foreach (var x in C)
Console.WriteLine(
string.Format(
"{0}:\t{1}",
x.Key,
string.Join(", ", x.Value)
)
);
The resulting output:
1: 11
2: 22, 222
3: 33, 333
4: 444
This is pretty much the same as if you wrote a "normal" foreach and would in fact work on any IEnumerable<KeyValuePair<decimal, long>> (not just SortedDictionary<decimal, long>) and is easy to extend to more than two input collections if needed.
Unfortunately, it also completely disregards the fact that the input SortedDictionary is, well, sorted, so performance is not optimal. For optimal performance you'd have to fiddle with linearly advancing separate IEnumerator for each of the input sorted dictionaries, while constantly comparing the underlying elements - you could completely avoid TryGetValue that way...

How to unifiy two arrays in a dictionary?

If you have two arrays string[] a and int[] b how can you get a Dictionary<string,int> from it most efficiently and with least code possible? Assume that they contain the same number of elements.
For example, is this the best way?
Dictionary<string,int> vals = new Dictionary<string,int>();
for(int i = 0; i < size; i++)
{
vals.Add(a[i],b[i]);
}
If your goal is to match at positions within the sequences, you can use Enumerable.Zip.
int[] myInts = { 1, 2 };
string[] myStrings = { "foo", "bar"};
var dictionary = myStrings.Zip(myInts, (s, i) => new { s, i })
.ToDictionary(item => item.s, item => item.i);
And since you are working with arrays, writing it "longhand" really isn't all that long. However, you want to validate beforehand the arrays truly are equal in length.
var dictionary = new Dictionary<string, int>();
for (int index = 0; index < myInts.Length; index++)
{
dictionary.Add(myStrings[index], myInts[index]);
}
Usually, Linq can result in more expressive, easier to understand code. In this case, it's arguable the opposite is true.
If this is .Net 4, then you can do the following:
var result = a.Zip(b, (first, second) => new {first, second})
.ToDictionary(val => val.first, val => val.second);
Without Zip, you can also do this:
var result = Enumerable.Range(0, a.Length).ToDictionary(i => a[i], i => b[i]);
Using ToDictionary:
int idx = 0;
var dict = b.ToDictionary(d => a[idx++]);
var result = a.ToDictionary(x => x, x => b[a.IndexOf(x)]);

Merging sequences by type With LINQ

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

Categories