I'm trying to find a LINQ oneliner that takes a Dictionary<String,Int> and returns a Dictionary<String,SomeEnum>....it might not be possible, but would be nice.
Any suggestions?
EDIT: ToDictionary() is the obvious choice, but have any of you actually tried it? On a Dictionary it doesn't work the same as on a Enumerable... You can't pass it the key and value.
EDIT #2: Doh, I had a typo above this line screwing up the compiler. All is well.
It works straight forward with a simple cast.
Dictionary<String, Int32> input = new Dictionary<String, Int32>();
// Transform input Dictionary to output Dictionary
Dictionary<String, SomeEnum> output =
input.ToDictionary(item => item.Key, item => (SomeEnum)item.Value);
I used this test and it does not fail.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
namespace DictionaryEnumConverter
{
enum SomeEnum { x, y, z = 4 };
class Program
{
static void Main(string[] args)
{
Dictionary<String, Int32> input =
new Dictionary<String, Int32>();
input.Add("a", 0);
input.Add("b", 1);
input.Add("c", 4);
Dictionary<String, SomeEnum> output = input.ToDictionary(
pair => pair.Key, pair => (SomeEnum)pair.Value);
Debug.Assert(output["a"] == SomeEnum.x);
Debug.Assert(output["b"] == SomeEnum.y);
Debug.Assert(output["c"] == SomeEnum.z);
}
}
}
var result = dict.ToDictionary(kvp => kvp.Key,
kvp => (SomeEnum)Enum.ToObject(typeof(SomeEnum), kvp.Value));
var collectionNames = new Dictionary<Int32,String>();
Array.ForEach(Enum.GetNames(typeof(YOUR_TYPE)), name =>
{
Int32 val = (Int32)Enum.Parse(typeof(YOUR_TYPE), name, true);
collectionNames[val] = name;
});
Related
I have a lookup like ths:
Lookup<String, pages> plsBase = (Lookup<String, pages>)(Query<pages>($#"Select ...").ToLookup(s => s.ip, o => o));
It is very fast when I access it by key, but the problem is that I need to access it with StartsWith().
When I use StartsWith() like below, the performance is comparable to a regular List
var pls = plsBase.Where(x => (x.Key.StartsWith(classBIp, StringComparison.Ordinal))).SelectMany(x => x).ToList();
The question is what can be done to improve the performance when using StartsWith()?
This answer assumes that classBIp is of a fixed length.
Option 1: Intermediate lookup [UPDATED]
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
namespace LookupTest
{
public class Tests
{
[Test]
public void IntermediateLookupTest()
{
var pageInfos = new Dictionary<string, string>
{
{ "Home", "home.html" },
{ "About", "about.html" },
{ "Fineprint", "fineprint.html" },
{ "Finish", "finish.html" },
{ "Above", "above.html" }
};
// Corresponds to OP: plsBase = (Lookup<String, pages>)(Query<pages>($#"Select ...").ToLookup(s => s.ip, o => o));
Lookup<string, string> plsBase = (Lookup<string, string>)pageInfos.ToLookup(k => k.Key, v => v.Value);
Lookup<string, string> intermediateLookup = (Lookup<string, string>)pageInfos.ToLookup(k => k.Key.Substring(0, 3), v => v.Key);
var classBIp = "Abo";
var result = new List<string>();
foreach (var plsBaseKey in intermediateLookup[classBIp])
{
result.AddRange(plsBase[plsBaseKey]);
}
Assert.AreEqual(2, result.Count);
Assert.True(result.Contains("about.html"));
Assert.True(result.Contains("above.html"));
}
}
}
Option 2: Compare a substring
var bipLength = classBip.Length;
var pls = plsBase.Where(x =>
(x.Key
.Substring(0, bipLength)
.Equals(classBIp, StringComparison.Ordinal)))
.SelectMany(x => x)
.ToList();
You might want to time both options to see which one performs better.
Declaring a list of objects:
List<object> result = new List<object>();
and a list of int to store the ids:
List<int> ids = new List<int>();
I want to store in result objects containing the pair (string, list of int).
It works fine for the pair (string, int) but I want that when there are 2 identical strings to have only one object and the int values to be stored in a list.
ex: {pars = "xxx", id = 1} , {pars = "xxx", id = 2} becomes {pars = "xxx", id = (1,2 )}
For doing the initial functionality, I use a foreach through an object from which I take the string(pars) and the id:
foreach (dataBinding in myData)
{
var x = string.Join(" ", dataBinding.Params.Select(p => p.myDescription));
result.Add(new { pars = x, id = dataBinding.Id });
}
there could be more strings in Params, that's why I use the join.
As it is here it works by creating objects having the form (string, int). But my aim is to make it (string, list of int) and if there are two objects with same string to combine them as I wrote before.
I tried to add ids list as the second property of the object but probably I'm not doing it correctly.
result.Add(new { pars = x, ids = dataBinding.Id });
You can use LINQ, especially GroupBy:
Dictionary<string, List<int>> descriptionIDs = myData
.GroupBy(x => x.myDescription)
.ToDictionary(g => g.Key, g => g.Select(x => x.Id).ToList());
Now you have even a dictionary, not just a strange List<object> that contains anonymous types.
As someone mentioned, you can also use ToLookup which i'd also prefer:
var descriptionLookup = myData.ToLookup(x => x.myDescription);
Now you can get the ID-List easily:
var result = descriptionLookup.Select(g => new { pars = g.Key, ids = g.Select(x=> x.Id).ToList() }).ToList():
Perhaps I am not understanding the scenario fully but I suspect using the following would server your purpose.
List<Dictionary<string, List<int>>>
When the key doesn't exist you add it and when it does you just add to the List.
Below program depicts the current generic collection type, also allow to add a new value if Key Already exists.
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
MyProgram p = new MyProgram();
p.Add("First" , 5);
p.Add("Second" , 8);
p.Add("Third" , 9);
p.Add("First" , 6);
p.Add("First" , 7);
p.PrintDictionary();
}
}
public class MyProgram
{
private Dictionary<string, List<int>> dict = new Dictionary<string, List<int>>();
public void Add(string key, int value)
{
if (dict.ContainsKey(key))
{
dict[key].Add(value);
}
else
{
dict.Add(key, new List<int>() {value});
}
}
public void PrintDictionary()
{
foreach(var keyValue in dict)
{
Console.WriteLine("Key : " + keyValue.Key);
foreach(var val in keyValue.Value)
{
Console.WriteLine(string.Format("\t Value : {0}", val));
}
}
}
}
Output :
Key : First
Value : 5
Value : 6
Value : 7
Key : Second
Value : 8
Key : Third
Value : 9
Check this Live Fiddle.
I have a string like this:
var strings1 = #"a={b},c={d},e={f},g={h},
i={j},k={l},m={n},o={p},q={r},s={t},u={v},w={x},
y={z}, alpha={beta}";
What am I trying to achieve is this:
Comma separate values
After separating them, trim down '{' and '}' chars from start and end.
Store them in a dictionary.
Output should be like this:
a,b
c,d
e,f //etc..,
Have written this program below and it works perfectly fine.
The question is, Are there any short / perfect way of doing this ?
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
var strings1 = #"a={b},c={d},e={f},g={h},
i={j},k={l},m={n},o={p},q={r},s={t},u={v},w={x},
y={z}, alpha={beta}";
var splitString = strings1.Split(',');
var splitList = splitString.ToList();
var output = new List<string>();
splitList.ForEach(x =>
{
output.Add(x.Trim());
});
splitList = new List<string>();
output.ForEach(x =>
{
splitList.Add(x.Trim());
});
var dict = new Dictionary<string, string>();
splitList.ForEach(x =>
{
var outpt = x.Split('=');
dict.Add(outpt[0], outpt[1]);
});
var dict1 = new Dictionary<string, string>();
foreach (var x in dict.Keys)
{
var val = dict[x];
var y = val.TrimStart('{').ToString().TrimEnd('}').ToString();
dict1.Add(x, y);
}
foreach(var y in dict1.Keys)
{
var stringFormatted = y + dict1[y];
Console.Write(stringFormatted);
Console.WriteLine();
}
}
}
Definitely. The following Linq code should give the same results.
var dictionary = yourString.Split(',')
.Select(x => x.Split('='))
.ToDictionary(x => x[0].Trim(), x => x[1].Trim('}','{',' '));
Note that like your code there is no error checking for entries that are missing the equal sign.
Very simple. Without LINQ, it would look like:
var strings1 = #"a={b},c={d},e={f},g={h},
i={j},k={l},m={n},o={p},q={r},s={t},u={v},w={x},
y={z}, alpha={beta}";
var splitString = strings1.Split(',');
var dict = new Dictionary<string, string>();
foreach (string s in splitString)
{
var splitPair = s.Split('=');
dict[splitPair[0].Trim()] = splitPair[1].Trim(' ', '{', '}');
}
I'm new working with c#, i have experience working with c++ and java. I'm trying to mess around with dictionaries but i cant really get this to work. I have two arrays the data type have to be objects, after i add them to two different dictionaries im trying to find a key within, but i cant get it to go into the if statements.Which of the two declarations of dictionary is correct dictionary1 or dictionary2? Also how can i find a value by the key or a key by the value in the correct dictionary or both.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Practice_With_Dictionaries
{
class Program
{
static void Main(string[] args)
{
object[] array1 = new object[5];
array1[0] = "1111";
array1[1] = "2222";
array1[2] = "3333";
array1[3] = "4444";
array1[4] = "5555";
object[] speed = new object[5];
speed[0] = 1;
speed[1] = 2;
speed[2] = 3;
speed[3] = 4;
speed[4] = 5;
object[] keys = new object[1];
keys[0] = (object[])array1;
object[] speedTable = new object[1];
speedTable[0] = (object[])speed;
Dictionary<object, object> dictionary1 = new Dictionary<object, object>();
Dictionary<object[], object[]> dictionary2 = new Dictionary<object[], object[]>();
dictionary1.Add(keys, speedTable);
dictionary2.Add(keys, speedTable);
if (dictionary1.ContainsKey((object)"1111"))
{
var method = 1;
}
if (dictionary2.ContainsKey(array1))
{
var method = 2;
}
}
}
}
dictionary1.ContainsKey((object)"1111") will never return true because "1111" will be boxed into a new unique object every time.
Populate one item at a time
You can populate the dictionary one item at a time:
Dictionary<object, object> dictionary1 = new Dictionary<object, object>();
for (int i = 0; i < array1.Length; i++)
{
dictionary1.Add(array1[i], speed[i]);
}
object key1 = array1[0];
if (dictionary1.ContainsKey(key1))
{
var method = 1;
}
Populate using LINQ
You can also populate the dictionary without explicit loops using LINQ and the ToDictionary(IEnumerable<TSource, Func<TSource, TKey>, Func<TSource, TElement>) method, which creates a Dictionary from an IEnumerable according to specified key selector and element selector functions.
Dictionary<object, object> dictionary2 = array1
.Select((obj, index) => new KeyValuePair<object, object>(array1[index], speed[index]))
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
Dictionary<object, object> dictionary3 = array1
.Select((obj, index) => index)
.ToDictionary(i => array1[i], i => speed[i]);
Dictionary<object, object> dictionary4 = Enumerable.Range(0,5)
.ToDictionary(i => array1[i], i => speed[i]);
The challenge with your code is that you are passing key values in a form of array or in others, they are using a list. Usually we initialize a Dictionary in a one to one relationship:
Dictionary<object, object> dict = new Dictionary<object, object>();
Sometimes in a one to many relationship:
Dictionary<object, object[]> dict = new Dictionary<object, object[]>();
In your case, you initialize it on a many to many relationship:
Dictionary<object[], object[]> dictionary2 = new Dictionary<object[], object[]>();
Although on your first example, particularly dictionary1, you still pass an array on your TKey value (see your code):
Dictionary<object, object> dictionary1 = new Dictionary<object, object>();
dictionary1.Add(keys, speedTable); //the value of keys consists of an object of an array: keys[0] = (object[])array1;
So your best shot is to implement your Dictionary with TKey of a single object, and TValue of an object or an array of object or a list of objects.
If you still want to do an array of object, you need to implement a custom IEqualityComparer since you cannot do what you are trying to do in your if statements.
Here is a sample generic implementation, you need to supply IEqualityComparer in your constructor Dictionary:
public class DictionaryComparer<T> : IEqualityComparer<List<T>>
{
public bool Equals(List<T> x, List<T> y)
{
//TODO: Your implementation for your contains or equals condition
}
public int GetHashCode(List<T> obj)
{
//TODO: Implementation of your GetHashCode
}
}
Then implement it:
if (new DictionaryComparer<object>().Equals(lstCompare, lstCompareTo))
{
//TODO: Your condition here..
}
Can someone provide me an example of how maybe I store different functions in a dictionary with int as a key and function as value. So then I could easly call function as following:
functionsDictionary[123](string);
Note all functions in dictionary will take only one input which is string. And will have no return.
It sounds like you're after
Dictionary<int, Action<string>>
or possibly (based on your title)
Dictionary<uint, Action<string>>
Sample:
using System;
using System.Collections.Generic;
class Test
{
static void Main()
{
var dictionary = new Dictionary<int, Action<string>>
{
{ 5, x => Console.WriteLine("Action for 5: {0}", x) },
{ 13, x => Console.WriteLine("Unlucky for some: {0}", x) }
};
dictionary[5]("Woot");
dictionary[13]("Not really");
// You can add later easily too
dictionary.Add(10, x => Console.WriteLine("Ten {0}", x));
dictionary[15] = x => Console.WriteLine("Fifteen {0}", x);
// Method group conversions work too
dictionary.Add(0, MethodTakingString);
}
static void MethodTakingString(string x)
{
}
}
Dictionary<int, Action<string>> _functions = new Dictionary<int, Action<string>>();
_functions[123]("hello");