I have the following Dictionary:
Dictionary<string, List<string>> myList = new Dictionary<string,List<string>>();
This dictionary gets populated, I'm never going to know how many items I will have.
An example of the output:
Elements of Dictionary: (Key,Value)
{"Code",{"Test1", "Test2", "Test3"}}
{"Desc",{"Desc1", "Desc2", "Desc3"}}
{"Name",{"name1", "name2", "name3"}}
How can I loop through every dictionary and get the value i.e. by index
something that would yield ->
{Code = "Test1", Desc = "desc", Name = "name1"}
{Code = "Test2", Desc = "desc2", Name = "name2"}
{Code = "Test3", Desc = "desc3", Name = "name3"}
Any ideas?
Thanks
The key is to build a set of arrays for each column of your data instead of for each rows like the Dictionary enumerator will provide you. This can be achieved through the use of the Aggregate extension method and a simple Select statement.
// Assuming the following class as a destination type
class Foo
{
public Foo(string[] values)
{
Code = values[0];
Name = values[1];
Desc = values[2];
}
public string Code;
public string Name;
public string Desc;
}
// This would be the code required to parse the data
var destination = dataSource["Code"].Aggregate(new List<Foo>(), (entries, _) =>
{
var curentRow = entries.Count();
var entryData = dataSource.Select(property => property.Value[curentRow]).ToArray();
entries.Add(new Foo(entryData));
return entries;
});
In this case, we use the Code property as a key to figure out how many entries there are in your data source (your dictionary). If there are rows in your dictionary with missing values (less items than in the Code row), this code will fail as it assumes that there are the same amount of items in all the rows.
The Aggregate method acts like a for loop in this case, providing us with a basic counter named currentRow that we will use later to access specific entries in your data. This counter is the amount of entries we stored into the List<Foo>. It starts at 0 and it increments each time we add a new value to the result set.
The next step is to look at all the entries in your data source and to access the value that matches the current row. We then convert it into an array and feeds it into the constructor of your destination type that knows how to deserialize this data.
This is a basic solution which perfectly solves your problem. I have created an IEnumerable object so that you can increment foreach loop by "Code","Desc",... .
Once you get the strings( which are Keys of Dictionary ) you can interate through the list that is the value of each key in the dictionary. The code below Writes and counts all elements in Dictionary and for each Values writes all elements in Lists.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
public static IEnumerable<string> Helper() // Neccessary to use in foreach loop
{
yield return "Code";
yield return "Desc";
yield break;
}
static void Main(string[] args)
{
Dictionary<string, List<string>> container = new Dictionary<string, List<string>>();
List<string> l1 = new List<string>();
List<string> l2 = new List<string>();
l1.Add("l1s1");
l1.Add("l1s2");
l1.Add("l1s3");
l2.Add("l2s1");
l2.Add("l2s2");
l2.Add("l2s3");
container.Add("Code", l1);
container.Add("Desc", l2);
int count = 0;
foreach (string k in Helper()) // get all Keys
{
for (int i = 0; i < container[k].Count; i++)
{
Console.WriteLine(container[k][i].ToString()); // Write each element in list
count++;
}
Console.WriteLine();
}
Console.WriteLine(count.ToString());
}
}
}
Note that you don't need to know how many elements will be in each list.Output is like :
Or without creating Helper() you can do like below:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Dictionary<string, List<string>> container = new Dictionary<string, List<string>>();
List<string> l1 = new List<string>();
List<string> l2 = new List<string>();
l1.Add("l1s1");
l1.Add("l1s2");
l1.Add("l1s3");
l2.Add("l2s1");
l2.Add("l2s2");
l2.Add("l2s3");
container.Add("Code", l1);
container.Add("Desc", l2);
int count = 0;
foreach (string k in new string [] {"Code","Desc"}) // get all Keys
{
for (int i = 0; i < container[k].Count; i++)
{
Console.WriteLine(container[k][i].ToString()); // Write each element in list
count++;
}
Console.WriteLine();
}
Console.WriteLine(count.ToString());
}
}
}
looks like the wrong data structure. Seems like you have a set of objects each with an arbitrary set of attributes. You need map<string,map<string,string>>
"item1"->code:'code1",desc:"desc1"....
"item2"->code:'code2",desc:"desc2", color:"red", size:'42"
......
Related
Can we create dynamic variable in C#?
I know my below code is threw error and very poor coding. But this code have small logic like create dynamic variable
var name=0;
for(i=0;i<10;i++)// 10 means grid length
{
name+i=i;
}
var xx1=name1;
var xx2=name2;
var xx3=name3;
Is it possible in c#? Create dynamic variable in c#? and change the variable name in c#? and concatenate the variable name in c#(like we can concatenate any control id or name)...
Why I need the dynamic variable name (scenario):
var variablename=""
var variablename0=No;
var variablename1=Yes;
var variablename2=No;
.
.
.
I have a gridview with multiple rows. And I need assign server side variable to every row. So I need set of variables in server side. the only I can set Text=<%# variablename+rowCount%> for every template field.
This rowCount means every grid row index.
If the grid has 2 rows, Then rowCount values are 0,1,2
Now I need to change the variablename to variablename0,variablename1,variablename2 dynamically for separate row.
C# is strongly typed so you can't create variables dynamically. You could use an array but a better C# way would be to use a Dictionary as follows. More on C# dictionaries here.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace QuickTest
{
class Program
{
static void Main(string[] args)
{
Dictionary<string, int> names = new Dictionary<string,int>();
for (int i = 0; i < 10; i++)
{
names.Add(String.Format("name{0}", i.ToString()), i);
}
var xx1 = names["name1"];
var xx2 = names["name2"];
var xx3 = names["name3"];
}
}
}
No. That is not possible. You should use an array instead:
name[i] = i;
In this case, your name+i is name[i].
Variable names should be known at compile time. If you intend to populate those names dynamically at runtime you could use a List<T>
var variables = List<Variable>();
variables.Add(new Variable { Name = inputStr1 });
variables.Add(new Variable { Name = inputStr2 });
here input string maybe any text or any list
try this one, user json to serialize and deserialize:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Script.Serialization;
namespace ConsoleApplication1
{
public class Program
{
static void Main(string[] args)
{
object newobj = new object();
for (int i = 0; i < 10; i++)
{
List<int> temp = new List<int>();
temp.Add(i);
temp.Add(i + 1);
newobj = newobj.AddNewField("item_" + i.ToString(), temp.ToArray());
}
}
}
public static class DynamicExtention
{
public static object AddNewField(this object obj, string key, object value)
{
JavaScriptSerializer js = new JavaScriptSerializer();
string data = js.Serialize(obj);
string newPrametr = "\"" + key + "\":" + js.Serialize(value);
if (data.Length == 2)
{
data = data.Insert(1, newPrametr);
}
else
{
data = data.Insert(data.Length-1, ","+newPrametr);
}
return js.DeserializeObject(data);
}
}
}
This is not possible, it will give you a compile time error,
You can use array for this type of requirement .
For your Reference :
http://msdn.microsoft.com/en-us/library/aa288453%28v=vs.71%29.aspx
we are doing the following programming exercise: Who's Online.
We have written the following code:
using System;
using System.Collections.Generic;
public static class Kata
{
public static Dictionary<UserStatus, IEnumerable<string>> WhosOnline /*❓❓*/ (User[] friends)
{
var users = new Dictionary<UserStatus, IEnumerable<string>>(); //We will save each friends' status and name
for(int i=0; i<friends.Length; i++)
{
Console.WriteLine(friends[i].Username+","+friends[i].Status+","+friends[i].LastActivity);
if(friends[i].Status==UserStatus.Online && friends[i].LastActivity>10){ //If it was active more than 10 minutes ago, it is away
friends[i].Status=UserStatus.Away;
}
users.Add(friends[i].Status, new []{friends[i].Username}); //We need to store the userStatus and its name
//users[friends[i].Status] = new []{friends[i].Username};
}
return users;
}
}
Being the tests:
namespace Solution
{
using NUnit.Framework;
using System;
using System.Collections.Generic;
[TestFixture]
public class SampleTest
{
[Test, Description("Example test two of each")]
public void SoloTest()
{
User[] friends = new User[]
{
new User("David", UserStatus.Online, 10),
new User("Anna", UserStatus.Online, 1),
new User("Lucy", UserStatus.Offline, 22),
new User("Viviana", UserStatus.Offline, 44),
new User("Bob", UserStatus.Online, 104),
new User("Fina", UserStatus.Online, 300),
};
var expected = new Dictionary<UserStatus, IEnumerable<string>>
{
{UserStatus.Online, new[] {"David"}},
{UserStatus.Online, new[] {"Anna"}},
{UserStatus.Offline, new[] {"Lucy"}},
{UserStatus.Offline, new[] {"Viviana"}},
{UserStatus.Away, new[] {"Bob"}},
{UserStatus.Away, new[] {"Fina"}}
};
Assert.That(Kata.WhosOnline(friends), Is.EqualTo(expected));
}
[Test, Description("Example test no one online")]
public void NoOnlineTest()
{
User[] friends = new User[]
{
new User("Lucy", UserStatus.Offline, 22),
new User("Bob", UserStatus.Online, 104)
};
var expected = new Dictionary<UserStatus, IEnumerable<string>>
{
{UserStatus.Offline, new[] {"Lucy"}},
{UserStatus.Away, new[] {"Bob"}}
};
Assert.That(Kata.WhosOnline(friends), Is.EqualTo(expected));
}
}
}
We found that it outputs:
System.ArgumentException : An item with the same key has already been added. Key: Online
We have identified that it is produced because of in the line 16:
users.Add(friends[i].Status, new []{friends[i].Username}); //We need to store the userStatus and its name
We are trying to assign a Dictionary entry, which key has been already inserted.
We would need to do something like the following:
users.Add(i, {friends[i].Status, new []{friends[i].Username}}); //We need to store the userStatus and its name
Adding to the dictionary each entry with a unique key. However if we execute the code with the previous line we get:
src/Solution.cs(17,20): error CS1525: Invalid expression term '{'
And if we execute it as follows:
users.Add(i, friends[i].Status, new []{friends[i].Username}); //We need to store the userStatus and its name
We observe:
src/Solution.cs(17,13): error CS1501: No overload for method 'Add' takes 3 arguments
In addition we also have tried to store entries like:
users[friends[i].Status] = new []{friends[i].Username};
However, it produces the same output:
System.ArgumentException : An item with the same key has already been added. Key: Online
Besides, we have adapted it as:
users[i] = (friends[i].Status,new []{friends[i].Username});
After that, we get:
src/Solution.cs(20,13): error CS1503: Argument 1: cannot convert from 'int' to 'UserStatus'
How could we insert new entries of UserStatus, IEnumerable, with unique keys?
We have read:
printing all contents of array in C#
Different ways of adding to Dictionary
Dictionary with object as value
C# appending Dictionary
Adding an item to a dictionary as the first item c#
Adding a dictionary element at a specific place
How to insert element in first index in dictionary?
C# Add elements to Dictionary with key as string and value as another Dictionary
EDIT: Thanks to #Guru Stron we have written the following code:
using System;
using System.Collections.Generic;
public static class Kata
{
public static Dictionary<UserStatus, IEnumerable<string>> WhosOnline /*❓❓*/ (User[] friends)
{
var users = new Dictionary<UserStatus, List<string>>(); //We will save each friends' status and name
for(int i=0; i<friends.Length; i++)
{
Console.WriteLine(friends[i].Username+","+friends[i].Status+","+friends[i].LastActivity);
if(friends[i].Status==UserStatus.Online && friends[i].LastActivity>10){ //If it was active more than 10 minutes ago, it is away
friends[i].Status=UserStatus.Away;
}
if(!users.ContainsKey(friends[i].Status)){ //-> We should check if this status has already been saved
users.Add(friends[i].Status, new List<string>{friends[i].Username});
}else{
users[friends[i].Status].Add(friends[i].Username);
}
}
return users;
}
}
However console writes:
src/Solution.cs(25,12): error CS0029: Cannot implicitly convert type 'System.Collections.Generic.Dictionary<UserStatus, System.Collections.Generic.List<string>>' to 'System.Collections.Generic.Dictionary<UserStatus, System.Collections.Generic.IEnumerable<string>>'
Because of we are trying to save a List inside a dictionary which has been declared as IEnumerable, and we can not change its type.
Then we tried, to convert it back to IEnumerable
using System;
using System.Collections.Generic;
public static class Kata
{
public static Dictionary<UserStatus, IEnumerable<string>> WhosOnline /*❓❓*/ (User[] friends)
{
var users = new Dictionary<UserStatus, List<string>>(); //We will save each friends' status and name
for(int i=0; i<friends.Length; i++)
{
Console.WriteLine(friends[i].Username+","+friends[i].Status+","+friends[i].LastActivity);
if(friends[i].Status==UserStatus.Online && friends[i].LastActivity>10){ //If it was active more than 10 minutes ago, it is away
friends[i].Status=UserStatus.Away;
}
if(!users.ContainsKey(friends[i].Status)){
users.Add(friends[i].Status, new List<string>{friends[i].Username});
}else{
users[friends[i].Status].Add(friends[i].Username);
}
}
var output = new Dictionary<UserStatus, IEnumerable<string>>(); //We try to convert List<string> back to IEnumerable<string>
foreach(KeyValuePair<UserStatus, List<string>> entry in users){
if(!output.ContainsKey(entry.Key)){
output.Add(entry.Key, entry.Value.ToArray());
}else{
users[entry.Key].Add(entry.Value.ToArray());
}
}
return output;
}
}
And we observe:
src/Solution.cs(29,30): error CS1503: Argument 1: cannot convert from 'string[]' to 'string'
After that, we followed the suggestion made by #Guru Stron and we started to use Linq as follows:
using System;
using System.Collections.Generic;
using System.Linq;
public static class Kata
{
public static Dictionary<UserStatus, IEnumerable<string>> WhosOnline /*❓❓*/ (User[] friends)
{
/*How could we express: if(f.Status==Online && f.LastActivity > 10) f.Status=Away ❗❓*/
var users = friends.GroupBy(f => f.Status).ToDictionary(g => g.Key,
g => (IEnumerable<string>)(g.Select(f => f.Username).ToList()));
foreach(KeyValuePair<UserStatus, IEnumerable<string>> entry in users)
{
Console.WriteLine("Status: "+entry.Key+" Username: ");
Console.WriteLine("[{0}]",string.Join(", ",entry.Value));
}
return users;
}
}
However, the tests fail because of we would need to express:
if(f.Status==Online && f.LastActivity > 10) f.Status=Away
How could do it with Linq?
Dictionary in C# is collection of unique keys and values associated with them.
So first of all you will want Dictionary<UserStatus, List<string>>() not Dictionary<UserStatus, IEnumerable<string>>()(for convenience). Secondary when adding a user to status group(key) you need to check if such group(key) exists and if yes - add to it, if not - add it:
if(!users.ContainsKey(friends[i].Status))
{
users.Add(friends[i].Status, new List<string>{friends[i].Username})
}
else
{
users[friends[i].Status].Add(friends[i].Username);
}
and lastly you can use LINQ:
var users = friends.GroupBy(f => f.Status)
.ToDictionary(g => g.Key, g => g.Select(f => f.UserName).ToList())
If you can't change signature of the your function LINQ would be more convenient cause you can do
var users = friends.GroupBy(f => f.Status)
.ToDictionary(g => g.Key,
g => (IEnumerable<string>)(g.Select(f => f.UserName).ToList()))
So I have this Hashtable
Hashtable Months = new Hashtable();
Months.Add(0, "JANUARY");
Months.Add(1, "FEBRUARY");
Months.Add(2, "MARCH");
Months.Add(3, "APRIL");
Months.Add(4, "MAY");
Months.Add(5, "JUNE");
Months.Add(6, "JULY");
Months.Add(7, "AUGUST");
Months.Add(8, "SEPTEMBER");
Months.Add(9, "OCTOBER");
Months.Add(10, "NOVEMBER");
Months.Add(11, "DECEMBER");
I would like for the user to enter a month e.g."May" the be able to retrieve index[4] from an array within my program.
string Month = Console.ReadLine();
Basically to retrieve the index from the number of the corresponding Month entered.
Try this
var key = Months.Keys.Cast<int>().FirstOrDefault(v => Months[v] == "MAY");
Note: Don't forget to include this namespace - using System.Linq;
Get elements from your Hashtable in DictionaryEntry format
foreach (DictionaryEntry e in Months)
{
if ((string)e.Value == "MAY")
{
//get the "index" with e.Key
}
}
You can perform it just using a loop;
public List<string> FindKeys(string value, Hashtable hashTable)
{
var keyList = new List<string>();
IDictionaryEnumerator e = hashTable.GetEnumerator();
while (e.MoveNext())
{
if (e.Value.ToString().Equals(value))
{
keyList.Add(e.Key.ToString());
}
}
return keyList;
}
Usage;
var items = FindKeys("MAY",Months);
If you want to lookup the index from the month's name, a Dictionary<string, int> would be more suitable. The reason why I've swapped the parameters is becuase if you only want to lookup the index, and not also the other way around, this will be much faster.
You should declare the dictionary as case-insensitive so that it detects for instance may, May, mAy and MAY as the same thing:
Dictionary<string, int> Months = new Dictionary<string, int>(StringComparison.OrdinalIgnoreCase);
Then just use its TryGetValue() method whenever you want to get the month index:
int MonthIndex = 0;
if(Months.TryGetValue(Month, out MonthIndex)) {
//Month was correct, continue your code...
else {
Console.WriteLine("Invalid month!");
}
I'm trying to get values from a collection, based on items whose IDs are in a certain collection of IDs.
My current code to build the filter is:
IEnumerable<string> IDList;
using (var enumerator = IDList.GetEnumerator())
{
if (enumerator.MoveNext() == false) return null; // empty collection
// take the first key
var key = enumerator.Current;
filter = Builders<MyClass>.Filter.Eq(p => p.Key, key);
// take all the other keys
while (enumerator.MoveNext())
{
var innerKey = enumerator.Current;
filter = filter | Builders<MyClass>.Filter.Eq(p => p.Key, innerKey);
}
}
and then my code to get the items is:
List<MyClass> values = new List<MyClass>();
using (var cursor = await MyCollection.FindAsync(filter))
{
while (await cursor.MoveNextAsync())
{
values.AddRange(cursor.Current);
}
}
This code's performance seems pretty subpar, and I'm sure there has to be a faster way since MongoDB should have very good performance... Not to mention I'm querying an indexed field, which should make the query very fast. What can I do to speed this up, both in an async way and a sync way? From some Googling I've seen that there are many ways to query a collection, and I'm not sure which way would be the best for my particular case.
Running this query in RoboMongo takes 0.02 seconds, while running it in C# MongoDb.Driver takes a full second, sometimes even longer and I'm not sure why.
Thanks in advance.
How about a simple "$in" query?
using MongoDB.Bson;
using MongoDB.Driver;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace ConsoleApp1
{
public class MyClass
{
public ObjectId Id;
public string Key;
}
public class Program
{
static void Main(string[] args)
{
IEnumerable<string> ids = new [] { "a", "b", "c" };
var collection = new MongoClient().GetDatabase("test").GetCollection<MyClass>("test");
foreach (var id in ids)
{
collection.InsertOne(new MyClass { Key = id });
}
// here comes the "$in" query
var filter = Builders<MyClass>.Filter.In(myClass => myClass.Key, ids);
// sync
List<MyClass> values = collection.Find(filter).ToList();
// async
var queryTask = collection.FindAsync(filter);
values = GetValues(queryTask).Result;
Console.ReadLine();
}
private static async Task<List<MyClass>> GetValues(System.Threading.Tasks.Task<IAsyncCursor<MyClass>> queryTask)
{
var cursor = await queryTask;
return await cursor.ToListAsync<MyClass>();
}
}
}
In a dictionary, I want to add a list of numbers for a given key.But I am unable to do it.
for(int i = 0 ; i < size ; i++){
string input = Console.ReadLine();
string[] inputList = input.Split(' ');
count[Convert.ToInt32(inputList[0])]++;
if(!map.ContainsKey(Convert.ToInt32(inputList[0]))){
map.Add(Convert.ToInt32(inputList[0]),new List<string>());
map_index.Add(Convert.ToInt32(inputList[0]),new List<int>());
}
}
The question is bit unclear. My understanding of your problem is as follows: You have a dictionary, a value of the dictionary is a list, and you have trouble adding an item to that list. Since you didn't explain your notation I'm using more general names, just to give you an idea what has to be done:
Dictionary<int, List<string>> myDict = new Dictionary<int, List<string>>();
if (myDict.ContainsKey(myKey))
{
myDict[myKey].Add(myVal);
}
else
{
myDict[myKey] = new List<string> { myVal };
}
If the key is not in the dictionary you create an entry together with the list and initialize the list with the new value. If the key is there you just access the list (by using myDict[myKey]) and add the new value to the list. Since the list is always created for a new key you don't have to worry that it's not initialized when adding a value for an existing key.
This could be one the efficient Solution and much easier than if-else.
Dictionary<int, List<string>> myDict = new Dictionary<int, List<string>>();
try
{
myDict[myKey].Add(myVal);
}
catch
{
myDict[myKey] = new List<string> { myVal };
}
There is a 'one-command-line' way to do this using AddOrUpdate from ConcurrentDictionary:
using System.Linq;
using System.Collections.Generic;
using System.Collections.Concurrent;
...
var dictionary = new ConcurrentDictionary<int, string[]>();
var itemToAdd = "item to add to key-list";
dictionary.AddOrUpdate(1, new[]{item1ToAdd}, (key, list) => list.Append(itemToAdd));
// If key 1 doesn't exist, creates it with a list containing itemToAdd as value
// If key 1 exists, adds item to already existent list (third parameter)