Largest key of nested dictionary in C# - c#

Tried searching online. But couldn't find an answer:
public class A
{
public Dictionary<int, string> Dict { get; } = new Dictionary<int, string>();
}
var list = new List<A>();
var a = new A();
a.Dict.Add(1, "A");
var b = new A();
b.Dict.Add(2, "A");
list.Add(a);
list.Add(b);
How to get the maximum and minimum key in dictionary.
max key is 2 and min key is 1.
var max = list.Max(e => e.Dict.??); //

You can use Dictionary.Keys property for this:
var max = list.Max(e => e.Dict.Keys.Max())
or
var max = list.SelectMany(e => e.Dict.Keys).Max()

Related

How to print the duplicates value while converting from Dictionary to List in c#

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);
}
}

Is there a LINQ-oriented method to quicky evaluate nested lists in dictionaries

I have a dictionary constructed like this:
Dictionary<string, List<MyObject>>
And my object has an integer value as one of its properties:
public class MyObject
{
public int number {get; set;}
}
How would I construct a LINQ-oriented query to evaluate the average number for each Key in the dictionary?
Depending on your needs
var results = dict.Select(
x => new
{
x.Key,
avg = x.Value.Average(y => y.number)
});
Or if you want your results in a dictionary
var results = dict.ToDictionary(x => x.Key, x => x.Value.Average(y => y.number));
Because dictionaries are enumerables, your request can be accomplished in a straightforward and natural manner
var averages = dictionary
.ToDictionary(pair => pair.Key, pair => pair.Value.Average(e => e.number));
Demo on dotnet fiddle
You can use Average to achieve it.
var data = new Dictionary<string, List<MyObject>>();
data.Add("1", new List<MyObject> { new MyObject { number = 1 }, new MyObject { number = 2 }, new MyObject { number = 3 }});
data.Add("2", new List<MyObject> { new MyObject { number = 4 }, new MyObject { number = 5 }, new MyObject { number = 6 }});
var result = data.Select(p => new { p.Key, Average = p.Value.Average(n => n.number) });

Sum on a dynamic list that has ExpandoObject as items

I have a dynamic list with ExpandoObject as items :
List<dynamic> list = new List<dynamic>();
foreach (...)
{
var dynamicObject = new ExpandoObject() as IDictionary<string, Object>;
...
list.Add(dynamicObject);
}
How can I use .Sum() on a dynamic list ? I know the names of the properties
of that list , but Sum() does not take a string as argument .
Thanks
Assuming you have list like this:
var list = new List<dynamic>
{
new ExpandoObject(),
new ExpandoObject(),
new ExpandoObject(),
};
list[0].Foo = 1;
list[1].Foo = 2;
list[2].Foo = 3;
you can use ExpandoObject's properties as regular properties, if their names are known at compile-time:
var sum1 = list
.Sum(item => item.Foo);
or use dictionary syntax, if property names are known at run-time only:
var sum2 = list
.Sum(item => (int)((IDictionary<string, object>)item)["Foo"]);
You can use Sum(Func<TSource, int> selector)
For you example :
var values = new int[] {1, 2, 3, 4, 5};
List<dynamic> list = new List<dynamic>();
foreach (var value in values)
{
var dynamicObject = new ExpandoObject() as IDictionary<string, Object>;
dynamicObject[value.ToString()] = value;
list.Add(dynamicObject);
}
// Kind of ugly as cast but otherwise it has trouble to find the Count property
var result = list.Sum(x => (x as IDictionary<string, Object>).Count);
Console.WriteLine("Result: {0}", result);
Console.ReadLine();
To my mind you could try this :
var listSum = list.Sum(item => item.GetType().GetProperty("propertyName").GetValue());
I called list the list on which you want to call the Sum method.
Let me know if the result is what you want.

C# Ordering 2 lists randomly

I have been trying to figure out how to randomly order two lists the same eg.
List<string> list = new List<string>();
list.Add("RedHat");
list.Add("BlueHat");
list.Add("YellowHat");
List<image> list2 = new List<image>();
list.Add(Properties.Resources.RedHat);
list.Add(Properties.Resources.BlueHat);
list.Add(Properties.Resources.YellowHat);
now if i wanted to order these so that redhat and the redhat image stay aligned how may i do this?And is there a way to combine these lists and then shuffle using a dictionary or keyvalue pair or something along those lines?
Wrap the two in an object:
class WrapperObject {
public string Name { get; set; }
public object Resource { get; set; }
}
Add them to a list:
var list = new List<WrapperObject>();
list.Add(new WrapperObject() {
Name = "RedHat",
Resource = Properties.Resources.RedHat
});
..randomize:
var rnd = new Random();
list = list.OrderBy(x => rnd.Next(50)).ToList();
Any specific reason why you want them in two lists, you could just create a list of keyvaluepairs like this:
var list = new List<KeyValuePair<string, image>> ();
list.Add(new KeyValuePair<string, image>("RedHat", (Properties.Resources.RedHat)));
list.Add(new KeyValuePair<string, image>("BlueHat", (Properties.Resources.BlueHat)));
list.Add(new KeyValuePair<string, image>("YellowHat", (Properties.Resources.YellowHat)));
You could store the data in a Tuple<,> but if you had more than 2 elements its worth just creating an explicit class to store the data.
Tuple example:
List<Tuple<string, image>> list = new List<Tuple<string, image>>();
list.Add(new Tuple<string,image>("RedHat", Properties.Resources.RedHat));
// etc...
LINQ-fu version:
var rng = new Random();
var res = Enumerable.Zip(list, list2, (e1, e2) => new { e1, e2 })
.OrderBy(x => rng.Next())
.Aggregate(new { list1 = new List<string>(), list2 = new List<image>() },
(lists, next) =>
{
lists.list1.Add(next.e1);
lists.list2.Add(next.e2);
return lists;
});
list = res.list1;
list2 = res.list2;
The following code should do what you want:
var list1 = new List<string>
{
"RedHat",
"BlueHat",
"YellowHat"
};
var list2 = new List<int>
{
1,
2,
3
};
var combined = list1.Zip(list2, (a, b) => new { a, b }).Shuffle(new Random()).ToList();
list1 = combined.Select(i => i.a).ToList();
list2 = combined.Select(i => i.b).ToList();
You'll need the following extension method:
public static class ShuffleExtension
{
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source, Random rng)
{
T[] elements = source.ToArray();
for (int i = elements.Length - 1; i >= 0; i--)
{
int swapIndex = rng.Next(i + 1);
yield return elements[swapIndex];
elements[swapIndex] = elements[i];
}
}
}
First put the corresponding elements together, then apply random order:
var rnd = new Random();
var ordered = list.Zip(list2, Tuple.Create).OrderBy(el => rnd.Next()).ToArray();
You can easily extract back the individual lists, if needed:
var ordered_list = ordered.Select(tuple => tuple.Item1).ToList();
var ordered_list2 = ordered.Select(tuple => tuple.Item2).ToList();

Generate a new list with key

i would like to create a new list with key and values
List<object> r = new List<object>();
r.Add("apple");
r.Add("John");
return r;
when u Addwatch the r, you will see
[1] = apple
[2] = John
Questions: How do i make the [1] and [2] to be new key? When i addwatch the r, i would like to see [1] is replaced by Name. something as below:
Name = apple
TeacherName = John
Do you mean you want to use something like Dictionary<TKey, TValue>
example:
Dictionary<string, string> d = new Dictionary<string, string>();
d.Add("Name", "Apple");
d.Add("Teacher", "John");
or do you want an object to more strongly typed?
in this case you have to use your one class / struct
class MyObject
{
public string Name {get; set;}
public string Teacher {get; set;}
}
Then
var list = new List<MyObject>();
list.Add(new MyObject { Name = "Apple", Teacher = "John" });
list.Add(new MyObject { Name = "Banana", Teacher = "Setphan" });
then you can all it
var item = list[0];
var name = item.Name;
var teacher = item.Teacher;
It is completely incorrect to use a list for this kind of a data structure. You need to use use Dictionary , NameValueCollection or similar type.
You can transform your list:
List<object> r = new List<object>();
r.Add("apple");
r.Add("John");
r.Add("orange");
r.Add("Bob");
var dict = r.Where((o, i) => i % 2 == 0)
.Zip(r.Where((o, i) => i % 2 != 0), (a, b) => new { Name = a.ToString(), TeacherName = b.ToString() });
foreach (var item in dict)
{
Console.WriteLine(item);
}
Output:
{ Name = apple, TeacherName = John }
{ Name = orange, TeacherName = Bob }
And then transform to dictionary:
var result = dict.ToDictionary(d => d.Name, d => d.TeacherName);
You will need to use a Dictionary to do this. Not a List.
See http://msdn.microsoft.com/en-us/library/xfhwa508.aspx
I hope i dont make any syntax mistakes here...
Dictionary <string, int> r = new Dictionary<string,int>();
r.add("apple",1);
r.add("John",2)
console.WriteLine(r["apple"]);//returns value 1
Your question is not clear and hard to understand.
Do you mean to say you want keys instead of indexes ? Like Name instead of 1
Well then as Aliza and Bumble Bee have said you need to use a Dictionary instead of a List.
Here's a small example
IDictionary<string, Interval> store = new Dictionary<string, string>();
store.Add("Name","apple");
store.Add("TeacherName ", John);
foreach(KeyValuePair<string, string> e in store)
Console.WriteLine("{0} => {1}", e.Key, e.Value);

Categories

Resources