My array:
string[] name = "a,b,c,d".Split(',');//key
string[] path = "w,x,y,z".Split(',');//value
List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
I try to assign a value like this.
foreach (string s in name)
{
foreach (string sp in path)
{
list.Add(new KeyValuePair<string, string>(s, sp));
}
}
But my logic is fail. What is a proper way to assign a KeyValue pair from two arrays?
Expected outcome.
a-w
b-x
c-y
d-z
Try using:
string[] names = "a,b,c,d".Split(','); //key
string[] paths = "w,x,y,z".Split(','); //value
var namesAndPaths = names.Zip(paths, (name, path) => new KeyValuePair<string,string>(name, path));
You must use the same loop for both arrays (or use the LINQ solutions proposed in other answers):
string[] name = "a,b,c,d".Split(','); // Key
string[] path = "w,x,y,z".Split(','); // Value
List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
for (int i = 0; i < name.Length, i++)
{
if (i == path.Length) // In case both arrays are not the same length
{
break;
}
list.Add(new KeyValuePair<string, string>(name[i], path[i]));
}
If you are sure that both arrays are equal length, you can do:
for (var i = 0; i < name.Length; ++i) {
list.Add(new KeyValuePair<string, string>(name[i], path[i]));
}
Assuming both arrays will be of same length you can do this -
for(int i=0; i<name.Length; i++)
{
list.Add(new KeyValuePair<string, string>(name[i], path[i]));
}
string[] name = "a,b,c,d".Split(','); //key
string[] path = "w,x,y,z".Split(','); //value
List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
for (int i = 0; i < name.Length; i++)
{
for (int j = 0; j < path.Length; j++)
{
if (i == j)
{
list.Add(new KeyValuePair<string, string>(name[i], path[j]));
}
}
}
You could do this using LINQ:
var mergedKeyValues = name.Select((n,i) => new KeyValuePair<string,string>(n,path[i]))
.ToList();
Output
[a, w]
,
[b, x]
,
[c, y]
,
[d, z]
Check out this demo.
Use a LINQ one-liner:
var d = name.Select((n, idx) => new { Name = n, Index = idx })
.ToDictionary(k => k.Name, v => path[v.Index]);
The key here is to use the index from the Select method to determine the index to use in the other array.
Related
I am trying to converting from dictionary to list while converting I am getting the output
I/p-
dic.Add("Demo1",2);
dic.Add("Demo2",1);
dic.Add("Demo3",1);
dic.Add("Demo4",2);
O/p-
Demo1
Demo2
Demo3
Demo4
But I need Demo1 and Demo4 two times because their quantity are 2. So How can I achieve that??
Below is the code
public IList<string> DictionaryToList(IDictionary<string,int> dictionary)
{
IDictionary<string, int> dic = new Dictionary<string, int>();
IList<string> lst = new List<string>();
dic.Add("Demo1",2);
dic.Add("Demo2",1);
dic.Add("Demo3",1);
dic.Add("Demo4",2);
foreach (var item in dic)
{
if (!lst.Contains(item.Key))
{
lst.Add(item.Key);
}
}
return lst;
}
}
class Program
{
static void Main(string[] args)
{
var conversion = new Conversion();
var list = new List<string> { "Demo1","Demo2","Demo3","Demo4","Demo1","Demo4"};
var dictionary = conversion.ListToDictionary(list);
foreach (var item in dictionary)
{
Console.WriteLine($"{item.Key}, {item.Value}");
}
var convertedList = conversion.DictionaryToList(dictionary);
foreach (var item in convertedList)
{
Console.WriteLine($"{item}");
}
Console.ReadLine();
}
Thanks in advance.
You can use LINQ's SelectMany and Enumerable.Repeat:
IList<string> list = dictionary
.SelectMany(kv => Enumerable.Repeat(kv.Key, kv.Value))
.ToList();
Here is also the opposite way to build your dictionary from the list:
var list = new List<string> { "Demo1", "Demo2", "Demo3", "Demo4", "Demo1", "Demo4" };
var dictionary = list.GroupBy(s => s).ToDictionary(g => g.Key, g => g.Count());
IList<string> list2 = dictionary
.SelectMany(kv => Enumerable.Repeat(kv.Key, kv.Value))
.ToList();
So at the end list2 contains the same strings as list but in a different order.
Your dictionary consists of a key (string) and a value (int). After checking
if (!list.Contains(item.Key)) just add another loop which goes from 0 to the actual value from your dictionary-item and adds the new item n-times.
for (int i = 0; i < item.Value; i++) // Demo1 and Demo4 runs 2x, Demo2 and Demo3 1x
lst.Add(item.Key);
Do you want something like this?
Dictionary<string, int> dic = new Dictionary<string, int>();
List<string> lst = new List<string>();
dic.Add("Demo1", 2);
dic.Add("Demo2", 1);
dic.Add("Demo3", 1);
dic.Add("Demo4", 2);
foreach (var item in dic)
{
for (int i = 0; i < item.Value; i++)
{
lst.Add(item.Key);
}
}
Below is the code where key is being hard-coded in Dictionary
var datalist = new List<IDictionary<string, string>>();
for (var i = 0; i < dt.Rows.Count; ++i)
{
var data = new Dictionary<string, string>()
{
{ "ID", Convert.ToString(dt.Rows[i]["ID"]) },
{ "STATUS", Convert.ToString(dt.Rows[i]["Name"]) },
{ "TYPE", Convert.ToString(dt.Rows[i]["TYPE"]) }
};
datalist.Add(data);
}
Now, instead of hard-coding the keys like ID, STATUS, etc, I want to add it from my string array containing the values below
string[] arrNames = ConfigurationManager.AppSettings["NameKey"].Split(',');
How can I traverse arrNamesto add keys in Dictionary and then add in List?
Iterate through the collection of names:
var datalist = new List<IDictionary<string, string>>();
string[] arrNames = ConfigurationManager.AppSettings["NameKey"].Split(',');
for (var i = 0; i < dt.Rows.Count; ++i)
{
var data = new Dictionary<string, string>();
foreach (var name in arrNames)
{
data[name] = Convert.ToString(dt.Rows[i][name]);
}
datalist.Add(data);
}
your code should look something like this
var datalist = new List<IDictionary<string, string>>();
string[] arrNames = Convert.ToString(ConfigurationManager.AppSettings["NameKey"]).Split(',');
if (arrNames.Length == 3)
{
for (var i = 0; i < dt.Rows.Count; ++i)
{
var data = new Dictionary<string, string>()
{
{ arrNames[0], Convert.ToString(dt.Rows[i][arrNames[0]]) },
{ arrNames[1], Convert.ToString(dt.Rows[i][arrNames[1]]) },
{ arrNames[2], Convert.ToString(dt.Rows[i][arrNames[2]]) }
};
datalist.Add(data);
}
}
You can use linq method ToDictionary. Try this code:
string[] arrNames = // new[] {"ID", "STATUS", "TYPE"};
var datalist = new List<IDictionary<string, string>>();
for (var i = 0; i < dt.Rows.Count; ++i)
datalist.Add(
arrNames
.Select(key =>
new
{
key,
value = Convert.ToString(dt.Rows[i][key])
}
)
.ToDictionary(x => x.key, x => x.value)
);
If you prefer LINQ-y and concise you could try something like:
var names = ConfigurationManager.AppSettings["NameKey"].Split(',');
var list = dt.AsEnumerable()
.Select(r => names.ToDictionary(n => n, n => r[n]))
.ToList();
Here I'm assuming dt is a DataTable.
If you have at least the same number of items in your arrNames array than columns you want to read and of course with this order, then you can hardcore the indexes.
var datalist = new List<IDictionary<string, string>>();
for (var i = 0; i < dt.Rows.Count; ++i)
{
var data = new Dictionary<string, string>()
{
{ arrNames[0], Convert.ToString(dt.Rows[i]["ID"]) },
{ arrNames[1], Convert.ToString(dt.Rows[i]["Name"]) },
{ arrNames[2], Convert.ToString(dt.Rows[i]["TYPE"]) }
};
datalist.Add(data);
}
I have a string message that is separated by ':Item:' I want to put the items next to ':Item:' in a dictionary using a unique key
string input = "aaaaa:Item:ID1222222:Item:ID3444444:Item:ID4555555";
var response = new Dictionary<string, string>();
string[] values = input.Split(':');
for (int i = 0; i < values.Length; i++)
{
if (!values[i].Contains("Item"))
{
// use the id as a unique key
response.Add(values[i].Substring(1, 3), values[i]);
}
Console.WriteLine(response["ID1"]);
Console.ReadLine();
}
But this is giving me a key not found exception since values[0] does not have the ID i used as a key.
How can I skip the first element in the collection? or is there another efficient way?
EDIT:
What I want to put in the dictionary is :
key = "AA", value = "aaaaa"
key = "ID1", value = "ID1222222"
key = "ID3" valeu ="ID3444444"
key = "ID4" value "ID4555555"
thanks
You can use LINQ to get your expected output:
var dictionary = input.Split(':')
.Where(x => !x.Contains("Item"))
.ToDictionary(x => x.Substring(0, 3), x => x);
Results in LINQPad:
Note: Substring might throw exception if you have a key that contains less than three characters,in order to fix that you can do the following:
var dictionary = input.Split(':')
.Where(x => !x.Contains("Item"))
.ToDictionary(x => x.Length >=3 ? x.Substring(0, 3) : x, x => x);
string input = "aaaaa:Item:ID1222222:Item:ID3444444:Item:ID4555555";
var response = new Dictionary<string, string>();
string[] values = input.Split(':');
for (int i = 1; i < values.Length; i++)
{
if (!values[i].Contains("Item"))
{
// use the id as a unique key
response.Add(values[i].Substring(0, 3), values[i]);
}
}
for (int i = 0; i < response.Count; i++)
{
if (response.ContainsKey("ID1"))
{
Console.WriteLine(response["ID1"]);
Console.ReadLine();
}
}
I have an array for example("1:2","5:90","7:12",1:70,"29:60") Wherein ID and Qty are separated by a ':' (colon), what I want to do is when there's a duplicate of IDs the program will add the qty and return the new set of arrays so in the example it will become ("1:72","5:90","7:12","29:60").
Ex.2 ("1:2","5:90","7:12","1:70","29:60","1:5") becomes ("1:77","5:90","7:12","29:60").
I want to solve it without using linq.
var foo = array.Select(s => s.Split(':'))
.GroupBy(x => x[0])
.Select(g =>
String.Format(
"{0}:{1}",
g.Key,
g.Sum(x => Int32.Parse(x[1]))
)
)
.ToArray();
Note, it's not necessary to parse the "keys," only the values.
Without LINQ:
var dictionary = new Dictionary<string, int>();
foreach (var group in array) {
var fields = group.Split(':');
if (!dictionary.ContainsKey(fields[0])) {
dictionary.Add(fields[0], 0);
}
dictionary[fields[0]] += Int32.Parse(fields[1]);
}
string[] foo = new string[dictionary.Count];
int index = 0;
foreach (var kvp in dictionary) {
foo[index++] = String.Format("{0}:{1}", kvp.Key, kvp.Value);
}
You have to do this manually. Loop through each list, check the ID for each element. Put it in a Dictionary<int, int>, Dictionary<id, qt>. If the dictionary contains the id, add it to the value.
Loop, add, check using Dictionary class.
If you want it without LINQ...
var totalQuantities = new Dictionary<int, int>();
foreach(var raw in sourceArr) {
var splitted = raw.Split(':');
int id = int.Parse(splitted[0]);
int qty = int.Parse(splitted[1]);
if(!totalQuantities.ContainsKey(id)) {
totalQuantities[id] = 0;
}
totalQuantities[id] += qty;
}
var result = new string[totalQuantities.Count];
int i=0;
foreach(var kvp in totalQuantities) {
result[i] = string.Format("{0}:{1}", kvp.Key, kvp.Value);
i++;
}
(
from raw in arr
let splitted = raw.Split(':')
let id = int.Parse(splitted[0])
let qty = int.Parse(splitted[1])
let data = new { id, qty }
group data by data.id into grp
let totalQty = grp.Sum(val => val.qty)
let newStr = string.Format("{0}:{1}", grp.Key, totalQty
select newStr
)
.ToArray()
Note that the code may contain accidental errors, as it was written in notepad.
var input=new string[]{"1:2","5:90","7:12","1:70","29:60","1:5"};
var result=input
.Select(s=>s.Split(':'))
.Select(x=>x.Select(s=>int.Parse(s)).ToArray())
.GroupBy(x=>x[0])
.Select(g=>g.Key+":"+g.Sum(x=>x[1]));
I was too lazy to specify the culture everywhere. You probably want to do that before putting it into production, or it will fail for cultures with unusual integer representations.
var totals=new Dictionary<int,int>
foreach(string s in input)
{
string[] parts=s.Split(':');
int id=int.Parse(parts[0]);
int quantity=int.Parse(parts[0]);
int totalQuantity;
if(!totals.TryGetValue(id,out totalQuantity))
totalQuantity=0;//Yes I know this is redundant
totalQuanity+=quantity;
totals[id]=totalQuantity;
}
var result=new List<string>();
foreach(var pair in totals)
{
result.Add(pair.Key+":"+pair.Value);
}
try this:
List<string> items = new List<string>(new string[] { "1:2", "5:90", "7:12", "1:70", "29:60" });
Dictionary<string, int> dictionary = new Dictionary<string, int>();
foreach (string item in items)
{
string[] data = item.Split(':');
string key = data[0];
if (!dictionary.ContainsKey(data[0]))
{
int value = dictionary[data[0]];
dictionary[key] += int.Parse(data[1]);
}
}
//Used dictionary values here
How to convert a String[] to an IDictionary<String, String>?
The values at the indices 0,2,4,... shall be keys, and consequently values at the indices 1,3,5,... shall be values.
Example:
new[] { "^BI", "connectORCL", "^CR", "connectCR" }
=>
new Dictionary<String, String> {{"^BI", "connectORCL"}, {"^CR", "connectCR"}};
I'd recommend a good old for loop for clarity. But if you insist on a LINQ query, this should work:
var dictionary = Enumerable.Range(0, array.Length/2)
.ToDictionary(i => array[2*i], i => array[2*i+1])
Dictionary<string,string> ArrayToDict(string[] arr)
{
if(arr.Length%2!=0)
throw new ArgumentException("Array doesn't contain an even number of entries");
Dictionary<string,string> dict=new Dictionary<string,string>();
for(int i=0;i<arr.Length/2;i++)
{
string key=arr[2*i];
string value=arr[2*i+1];
dict.Add(key,value);
}
return dict;
}
There's really no easy way to do this in LINQ (And even if there were, it's certainly not going to be clear as to the intent). It's easily accomplished by a simple loop though:
// This code assumes you can guarantee your array to always have an even number
// of elements.
var array = new[] { "^BI", "connectORCL", "^CR", "connectCR" };
var dict = new Dictionary<string, string>();
for(int i=0; i < array.Length; i+=2)
{
dict.Add(array[i], array[i+1]);
}
Something like this maybe:
string[] keyValues = new string[20];
Dictionary<string, string> dict = new Dictionary<string, string>();
for (int i = 0; i < keyValues.Length; i+=2)
{
dict.Add(keyValues[i], keyValues[i + 1]);
}
Edit: People in the C# tag are damn fast...
If you have Rx as a dependency you can do:
strings
.BufferWithCount(2)
.ToDictionary(
buffer => buffer.First(), // key selector
buffer => buffer.Last()); // value selector
BufferWithCount(int count) takes the first count values from the input sequence and yield them as a list, then it takes the next count values and so on. I.e. from your input sequence you will get the pairs as lists: {"^BI", "connectORCL"}, {"^CR", "connectCR"}, the ToDictionary then takes the first list item as key and the last ( == second for lists of two items) as value.
However, if you don't use Rx, you can use this implementation of BufferWithCount:
static class EnumerableX
{
public static IEnumerable<IList<T>> BufferWithCount<T>(this IEnumerable<T> source, int count)
{
if (source == null)
{
throw new ArgumentNullException("source");
}
if (count <= 0)
{
throw new ArgumentOutOfRangeException("count");
}
var buffer = new List<T>();
foreach (var t in source)
{
buffer.Add(t);
if (buffer.Count == count)
{
yield return buffer;
buffer = new List<T>();
}
}
if (buffer.Count > 0)
{
yield return buffer;
}
}
}
It looks like other people have already beaten me to it and/or have more efficient answers but I'm posting 2 ways:
A for loop might be the clearest way to accomplish in this case...
var words = new[] { "^BI", "connectORCL", "^CR", "connectCR" };
var final = words.Where((w, i) => i % 2 == 0)
.Select((w, i) => new[] { w, words[(i * 2) + 1] })
.ToDictionary(arr => arr[0], arr => arr[1])
;
final.Dump();
//alternate way using zip
var As = words.Where((w, i) => i % 2 == 0);
var Bs = words.Where((w, i) => i % 2 == 1);
var dictionary = new Dictionary<string, string>(As.Count());
var pairs = As.Zip(Bs, (first, second) => new[] {first, second})
.ToDictionary(arr => arr[0], arr => arr[1])
;
pairs.Dump();
FYI, this is what I ended up with using a loop and implementing it as an extension method:
internal static Boolean IsEven(this Int32 #this)
{
return #this % 2 == 0;
}
internal static IDictionary<String, String> ToDictionary(this String[] #this)
{
if (!#this.Length.IsEven())
throw new ArgumentException( "Array doesn't contain an even number of entries" );
var dictionary = new Dictionary<String, String>();
for (var i = 0; i < #this.Length; i += 2)
{
var key = #this[i];
var value = #this[i + 1];
dictionary.Add(key, value);
}
return dictionary;
}
Pure Linq
Select : Project original string value and its index.
GroupBy : Group adjacent pairs.
Convert each group into dictionary entry.
string[] arr = new string[] { "^BI", "connectORCL", "^CR", "connectCR" };
var dictionary = arr.Select((value,i) => new {Value = value,Index = i})
.GroupBy(value => value.Index / 2)
.ToDictionary(g => g.FirstOrDefault().Value,
g => g.Skip(1).FirstOrDefault().Value);