How to create more 2 arguments in a dictionary? - c#

I'm trying to a build a simple app and the main point is I must use dictionary. I will have data like this in my dictionary:
(key,number,number,number,number)
So below is my code which implements my data.
Dictionary<string,int,int,int,int> states = new Dictionary<string,int,int,int,int>();
I have looked at many sources for how to solve it, but I couldn't find it.
I get an error that it must have a two arguments.
Can you give me a solution to make a dictionary can hold more than 2 arguments?

You can create a class to hold the 4 numbers like this:
public class MyData
{
public int Number1 {get;set;}
public int Number2 {get;set;}
public int Number3 {get;set;}
public int Number4 {get;set;}
}
And use it as the dictionary value type like this:
Dictionary<string,MyData> states = new Dictionary<string,MyDate>();
Here is a code example that adds an item to the dictionary:
states.Add("my_key", new MyData { Number1 = 1, Number2 = 2, Number3 = 3, Number4 = 4});
To access data for a specific key, you can use:
MyData data = states["my_key"];
int number1 = data.Number1;
//...
To iterate over all data, you can use a simple foreach like this:
foreach(var kvp in states)
{
var key = kvp.Key;
var data = kvp.Value;
var number1 = data.Number1;
//...
}
Another alternative for MyData would be the Tuple class. But having your own type is probably better because you can have your own names for the 4 number properties.

If the names of the last four integers does not matter, you can use
Dictionary<string, List<int>>
By this way, you can get your int list with your string key, and then enumerate the list.
OR you can go with any array type such as
Dictionary<string, int[]>

Related

Indexes that correspond to each other in two Lists

I have two Lists:
List<string> names = new List<string>();
List<int> goals = new List<int>();
One of them is a string List while the other one is a int List. I add some numbers in the second List, and then I get the biggest number in the List. This works.
Now I need to type some names in the console and after each name I need to type a certain number and this repeats to whenever I want.
How do I get the index of the biggest number in the second list and to print it alongside the name that actually have "scored" that biggest number? I want to get the index from the first string List that corresponds to the index of the biggest number in the second List. Is there a way that I can do it?
In your case, "Name" and "Goals" relate to each other. Someone or something with a "Name" has obviously attached to them a number of "Goals". So, let's reflect this relation in a class:
public class StatisticsItem
{
// Properties here
public string Name {get; set;}
public int Goals {get; set;}
}
You then can create new instances of that class like so:
var item = new StatisticsItem() { Name = "Marc", Goals = 5 };
and you can put those in a list:
var myList = new List<StatisticsItem>();
myList.Add(item);
Find your champion:
using System.Linq;
// ...
Console.WriteLine("Goalie King: {0}", myList.MaxBy(x => x.Goals).Name);
See in action: https://dotnetfiddle.net/I9w5u7
To be a bit more clean, you could of course use a constructor:
public class StatisticsItem
{
// Properties here
public string Name {get; set;}
public int Goals {get; set;}
public StatisticsItem(string name, int goals)
{
Name = name;
Goals = goals
}
}
// and then create instances like so:
var item = new StatisticsItem("Marc", 5);
Can't comment so i will add my opinion here. Fildor suggested 1 list with 2 properties which should cover your case. I would say also check if a dictionary<string, int> or a dictionary<string, List<int>> is a better fit instead of a list.
Keep in mind for a dictionary to work the key (name in your case) must be unique. If not discard this answer

Iterating over lists and summing and putting result in dictionary

Suppose i have two (could be more) lists of same object having same fields/properties.
Each list represent the same object
Proerpties:
HoursWorked
HoursRate
I want to take iterate and take sum of each field from all lists (could be 2, 3, or so on) and store it in an dictionary with key value pair. e.g HoursWorked:2 and HourseRate:6
Currently, i am able to do it for only one field only (hard coded). I want to make it generic so i can fill dictionary with Key/Value for all fields.
I have defined my dictionary as follow
public Dictionary<string, double> TotalCount { get; set; }
Linq Query:
Dictionary<string, double> totalCount = records
.GroupBy(x => records)
.ToDictionary(x => Convert.ToString("HoursWorked"), x => x.Where(y => y.HoursWorked != null).Sum(y => y.HoursWorked).Value);
Any help on this?
Sample Data:
Input
report =
{
[HoursWorked: 1.0, HoursRate:10],
[HoursWork:2.0, HoursRate:15]
}
Expected Output
Dictioary = {Key:HoursWorked Value: 3.0,Key:HoursRate Value:25}
Dictionary<string, double> dictionary = new[] { "HoursWorked", "HoursRate" }
.ToDictionary(k => k, v => collections
.SelectMany(x => x)
.Sum(y => (double)y.GetType().GetProperty(v).GetValue(y)));
Where 'collections' is your collection of lists.
Obviously totally type unsafe and will fall down very easily!
I would argue that a much better pattern for this, as opposed to using reflection, would be to write a method or interface that will return the correct double value given the string key.
class someObject
{
public int workingHours { get; set; }
public int hourRate { get; set; }
}
You can create a common list from all list.
List<SomeObject> lst = new List<SomeObject>();
lst.AddRange(Oldlst1);
lst.AddRange(Oldlst2);
Then you can group by based on hour rate.
var n = lst.GroupBy(x=>x.hourRate);
And then you can create a dictionary.
var m=n.ToDictionary(x=>x.Key, x=>x.Sum(y=>y.workingHours));
Here in m you will get hourRate and in value you will get sum of working hour.

Prevent double lookup of the same element in Dictionary

I know there is no reference to "struct" variable in C#, but this is the case where it would come handy
Dictionary<int, int> d = new Dictionary<int, int>();
d.Add(1, 1);
++d[1];
++d[1];
how can I perform 2 operations (increment in this case) on the same element without using operator[] twice (to prevent double lookup)?
You can create a mutable reference type that wraps another value, in this case an immutable value type, allowing the value of the wrapper to be mutated:
public class Wrapper<T>
{
public T Value { get; set; }
}
This lets you write:
Dictionary<int, Wrapper<int>> d = new Dictionary<int, Wrapper<int>>();
d.Add(1, new Wrapper<int>(){Value = 1});
var wrapper = d[1];
wrapper.Value++;
wrapper.Value++;

which c# collection to use instead of List<KeyValuePair<string, double>>?

I want to store data such as
{
{"apple",15 }
{"pear",12.5 }
{"", 10 }
{"", 0.45 }
}
Data will be plotted on a bar chart (string will be the legend and double will be the value)
Insert order is important.
Perfs don't matter.
Strings could be duplicated or empty. (values could be duplicated too)
I need to get min and max values (easily if possible) to set the scale.
I use
List<KeyValuePair<string, double>> data = new List<KeyValuePair<string, double>>();
data.Add(new KeyValuePair<string,double>("",i));
Quite boring and unreadable.
Is there a cleaner way to do it ?
StringDoubleCollection data = new StringDoubleCollection();
data.add("apple",15);
data.add("",10);
double max = data.values.Max();
double min = data.values.Min();
if not how to get the max value of List<KeyValuePair<string, double>> without too much hassle
NameValueCollection looks nice but its a <string,string> I need a <string,double>
You could create a class like the following:
class X
{
public string Name { get; set; }
public double Value { get; set; }
// name is an optional parameter (this means it can be used only in C# 4)
public X(double value, string name = "")
{
this.Name = name;
this.Value = value;
}
// whatever
}
And then get maximum and minimum values using LINQ with a selector:
var data = new List<X>();
data.Add(new X(35.0, "Apple"))
data.Add(new X(50.0));
double max = data.Max(a => a.Value);
double min = data.Min(a => a.Value);
EDIT: if the code above still seems unreadable to you try to improve it using an operator for cases in which you want to have just the value.
// Inside X class...
public static implicit operator X(double d)
{
return new X(d);
}
// Somewhere else...
data.Add(50.0);
To determine which data structure you really want, lets look at your usage patterns.
Insert order matters.
You don't access your items by key.
You want min and max.
A heap offers min or max, but doesn't preserve order. A hash based dictionary also doesn't preserve order. A List is actually a good choice for your data structure. It is available and offers excellent support.
You can prettify your code by defining classes for both the data structure and your bar data. And you can add min/max functionality to the collection. Note: I didn't use the Linq Min/Max functions, because they return the minimum value, not the minimum element.
public class BarGraphData {
public string Legend { get; set; }
public double Value { get; set; }
}
public class BarGraphDataCollection : List<BarGraphData> {
// add necessary constructors, if any
public BarGraphData Min() {
BarGraphData min = null;
// finds the minmum item
// prefers the item with the lowest index
foreach (BarGraphData item in this) {
if ( min == null )
min = item;
else if ( item.Value < min.Value )
min = item;
}
if ( min == null )
throw new InvalidOperationException("The list is empty.");
return min;
}
public BarGraphData Max() {
// similar implementation as Min
}
}
Have you looked at LookUp?
The only problem is that it's immutable, so you need to be able to create your collection in one go.
As Anthony Pegram notes, it's a bit of a pain to create one. It depends on where your data is coming from. Have a look at the ToLookup method.
If it's worth it for usability (i.e. you're using awkward collections of List<KeyValuePair<string, double>> everywhere, it might just be worth it to implement StringDoubleCollection. It wouldn't be that difficult to wrap the underlying collection with the friendlier syntax you've described in your example.
And, as other comments / answers are suggesting, the Framework doesn't seem to provide a simpler solution that matches all of your requirements...
As for "max value", I assume you mean the Key-Value Pair with the greatest value. It can be retrieved like so:
var max = list.Select(kvp => kvp.Value).Max();
Just define your own model class to hold the data instead of depending on a KeyValuePair and everything becomes cleaner:
using System;
using System.Collections.Generic;
public class Fruit
{
public string Name {get; set;}
public double Price {get; set;}
}
public class Program
{
public static void Main()
{
List<Fruit> _myFruit = new List<Fruit>();
_myFruit.Add(new Fruit{Name="apple", Price=15 });
_myFruit.Add(new Fruit{Name="pear", Price=12.5 });
_myFruit.Add(new Fruit{Name="", Price=10 });
_myFruit.Add(new Fruit{Name="", Price=0.45 });
// etc...
}
}
What about implementing the StringDoubleCollection to work like you want...
public class StringDoubleCollection
{
private List<KeyValuePair<string, double>> myValues;
public List<double> values
{
get { return myValues.Select(keyValuePair => keyValuePair.Value).ToList(); }
}
public void add(string key, double value)
{
myValues.Add(new KeyValuePair<string,double>(key,value));
}
}
You can implementing Dictionary<key, value>
Dictionary<string, string> openWith = new Dictionary<string, string>();
openWith.Add("txt", "notepad.exe");
openWith.Add("bmp", "paint.exe");
openWith.Add("dib", "paint.exe");
openWith.Add("rtf", "wordpad.exe");
https://learn.microsoft.com/pt-br/dotnet/api/system.collections.generic.dictionary-2?view=net-5.0

Change arraylist to generic

I am using below code :
var list = new Collection<ArrayList>
{
new ArrayList
{
1,
"Test1"
},
new ArrayList
{
2,
"Test2"
},
};
In the above code I want to avoid the ArrayList and use the Generics. Is it possible in the above code?
Edit:
Above I have used only two values in one arraylist object, I may have multiple items of int's and string's in it.
You can't mix types in a generic list (unless the generic type is object, but that equates to ArrayList and is just a perversion of generics).
But you can create a class that contains a string and int and use that as the generic parameter for a generic list.
public class MyClass
{
public MyString string { get; set; }
public MyInt int { get; set; }
}
var list = new Collection<MyClass>
{
new MyClass { MyInt = 1, MyString = "Test1" },
new MyClass { MyInt = 2, MyString = "Test2" }
}
Another alternative, if using .NET 4.0 is to use a Tuple, though I would rather have a strongly typed class.
(untested code):
var list = new Collection<Tuple<int,string>>
{
Tuple.Create(1, "Test1"),
Tuple.Create(2, "Test2")
}
No.
The whole point of generics is that you can't put an int and a string in the same collection.
Instead, you should create your own class with int and string properties, then create a generic collection of that class.
Not really, the fact that you have different types makes using a generic pointless.
You could use List<object> instead of ArrayList but there's really no point. Instead you could create a custom class to hold the 2 values and use that in a generic type.
John
Maybe you need Dictionary?
var list = new Dictionary<int, string>
{
{ 1, "Test1" },
{ 2, "Test2" }
};
var list = new List < Dictionary<int, string>> ();
then you can populate it was data as you need.
I'm not sure what you are actually trying to achieve, but it seems to me you are trying to mimic the behavior of a dictionary or map, that can map two different values to each other. These values could be of any type you want.
Something like this:
Dictionary<int, string> d = new Dictionary<int, string>();
d.Add(1, "Test1");
d.Add(2, "Test2");
and you can handle your data as simple as:
string t1 = d[1]; //will hold "Test1"
string t2 = d[2]; //will hold "Test2"
Do you want something like this?

Categories