Generic Dictionary retrieve value - c#

I have the following C# class:
class BatchData
{
public string batchNumber { get; set; }
public string processDate { get; set; }
public int TotalRecords { get; set; }
public int SuccessCount { get; set; }
}
and a dictionary:
Dictionary<int, BatchData> BatchData = new Dictionary<int, BatchData>();
Now, I want to search the whole dictionary to see if the value
x
is held in:
BatchData.batchNumber
eg
for the whole dictionary, if
BatchData.batchNumber = x
I know Dictionary has a method
.contains
But I am not sure how I can apply this.
EDIT:
BatchData.batchNumber = x
Can occur multiple times within the dictionary

You could do this:
BatchData.Values.Any(x=>x.batchNumber == "x");
For example:
Dictionary<int, BatchData> BatchData = new Dictionary<int, BatchData>();
BatchData.Add(1, new BatchData { batchNumber = "x"});
var hasX = BatchData.Values.Any(x=>x.batchNumber == "x"); //true;

A dictionary is a collection of KeyValuePair objects, each of which has a Key property (an int in your case), and a Value property (a BatchData object).
There could be multiple entries with that batch number. If you just want to see if any key contains that number you can use
batchData.Any(kvp => kvp.Value.batchNumber == x);
If you want all key-value pairs with that batch number, change to Where:
batchData.Where(kvp => kvp.Value.batchNumber == x);
You can also use First, Single, etc. as appropriate.

You should use batchNumber as the key to your dictionary:
Dictionary<string, BatchData> BatchData = new Dictionary<string, BatchData>();
BatchValues.Add(batch1.batchNumber, batch1);
BatchValues.Add(batch2.batchNumber, batch2);
BatchValues.Add(batch3.batchNumber, batch3);
...
Then checking for existence is an O(1) operation (link):
BatchValues.ContainsKey(batchNumber);

You can use another one solution by Contains method from System.Linq.
First, you need to implement IEqualityComparer<> interface
public class BatchDataComparer : IEqualityComparer<KeyValuePair<int, BatchData>>
{
public bool Equals(KeyValuePair<int, BatchData> x, KeyValuePair<int, BatchData> y)
{
return (x.Value.batchNumber == y.Value.batchNumber);
}
public int GetHashCode(KeyValuePair<int, BatchData> obj)
{
//or something else what you need
return obj.Value.batchNumber.GetHashCode();
}
}
After that, you can get value from Dictionary like this:
private static void Main(string[] args)
{
Dictionary<int, BatchData> dic = new Dictionary<int, BatchData>();
dic.Add(1, new BatchData() { batchNumber = "x" });
dic.Add(2, new BatchData() { batchNumber = "y" });
dic.Add(3, new BatchData() { batchNumber = "z" });
bool contain = dic.Contains(new KeyValuePair<int, BatchData>(100, new BatchData()
{
batchNumber = "z"
}), new BatchDataComparer());
Console.ReadKey();
}
public class BatchData
{
public string batchNumber { get; set; }
public string processDate { get; set; }
public int TotalRecords { get; set; }
public int SuccessCount { get; set; }
}

Related

C# Add element to an Object List using variable as List key

Let me explain, I have a model list in which I have a little more than a thousand parameters, so I have to fill the list with some variables, the thing is that I don't want to do this:
list.Add(new Model{
name1= value,
name2= value,
.....
name1000=value
});
I have an array that contains the names of the parameters in the list, so I was wondering if is possible to use that array of the names and in a loop get the variables fill in, something like this:
list.Add(new Model{
//a loop?
array[0]= value
});
Thanks.
You can achieve this using reflection. Code below
public class ModelFactory
{
private IDictionary<string, PropertyInfo> propertiesInfo { get; set; }
public ModelFactory()
{
this.propertiesInfo = typeof(Model)
.GetProperties()
.ToDictionary(p => p.Name, p => p);
}
public Model Create(string[] propertiesToInitialize, dynamic value)
{
var model = new Model();
foreach (var propertyName in propertiesToInitialize)
{
if (this.propertiesInfo.ContainsKey(propertyName))
{
var property = this.propertiesInfo[propertyName];
property.SetValue(model, value);
}
}
return model;
}
}
Model to initialize
public class Model
{
public int MyProperty1 { get; set; }
public int MyProperty2 { get; set; }
public int MyProperty3 { get; set; }
public int MyProperty4 { get; set; }
public int MyProperty5 { get; set; }
}
Usage
public void Test()
{
var propertiesToInitialize = new string[] { "MyProperty1", "MyProperty2", "MyProperty4" };
var modelFactory = new ModelFactory();
var list = new List<Model>();
list.Add(modelFactory.Create(propertiesToInitialize, 500));
Console.WriteLine("MyProperty1 " + list[0].MyProperty1); // 500
Console.WriteLine("MyProperty2 " + list[0].MyProperty2); // 500
Console.WriteLine("MyProperty3 " + list[0].MyProperty3); // 0
Console.WriteLine("MyProperty4 " + list[0].MyProperty4); // 500
Console.WriteLine("MyProperty5 " + list[0].MyProperty5); // 0
}
However as already mentioned in comments, please reconsider your model design because model with these many properties is not optimal.

Using custom object as dictionary key but get values by object property

I have a class:
public class Foo
{
public string Name { get; set; }
public double Value { get; set; }
public override string ToString()
{
return Name;
}
}
And I need to create a dictionary where key is object of Foo. Like this:
Foo foo1 = new Foo { Name = "Foo1", Value = 2.2 };
Foo foo2 = new Foo { Name = "Foo2", Value = 3.6 };
Dictionary<Foo, int> dic = new Dictionary<Foo, int>();
dic.Add(foo1, 1234);
dic.Add(foo2, 2345);
And now I want to get values from dictionary by passing Foo.Name property as key. Like this:
int i=dic["Foo1"];
// i==1234
i = dic["Foo2"];
// i==2345
Is it possible? Or the only way to pass object of Foo as key and override Equals method?
If you use a Foo as a key, you will need to use a Foo to index the dictionary as well.
Provided that what you actually need is most likely a Dictionary<string, int>, you could try overriding GetHashCode and Equals so that you can compare Foo objects based on the name only:
using System.Collections.Generic;
public class Foo {
public string Name { get; set; }
public double Value { get; set; }
public override string ToString() {
return Name;
}
public override int GetHashCode() {
return Name.GetHashCode();
}
public override bool Equals(object obj) {
Foo other = obj as Foo;
if (other == null) {
return false;
}
return Name.Equals(other.Name);
}
}
class Program {
static void Main(string[] args) {
Foo foo1 = new Foo { Name = "Foo1", Value = 2.2 };
Foo foo2 = new Foo { Name = "Foo2", Value = 3.6 };
Dictionary<Foo, int> dic = new Dictionary<Foo, int>();
dic.Add(foo1, 1234);
dic.Add(foo2, 2345);
int i = dic[new Foo { Name = "Foo1" }];
}
}
How about this:
class Program
{
public class Foo
{
public string Name { get; set; }
public double Value { get; set; }
public override string ToString()
{
return Name;
}
}
static void Main(string[] args)
{
Foo foo1 = new Foo { Name = "Foo1", Value = 2.2 };
Foo foo2 = new Foo { Name = "Foo2", Value = 3.6 };
var dic = new Dictionary<string, KeyValuePair<Foo, int>>();
dic.Add(foo1.Name, new KeyValuePair<Foo, int>(foo1, 1234));
dic.Add(foo2.Name, new KeyValuePair<Foo, int>(foo2, 2345));
int x = dic["Foo1"].Value;
var y = dic["Foo2"].Value;
Console.WriteLine(x);
Console.WriteLine(y);
Console.ReadKey();
}
}
Result will be:
1234
2345
The Dictionary is based on a hash table, that means it uses a hash lookup, which is a rather efficient algorithm to look up things. I suggest you think on your design and just use Dictionary<string,int>if you just want to use string as key
As a work around( not preferred way use only if you can't change your design), you could do this.
var key = dic.Keys.FirstOrDefault(c=>c.Name == "Foo1");
if(key != null)
dic[key]; //
Ok. I solved it by creating a class inherits Dictionary and overriding get value method. This solves my problem but I'm not sure about productivity with large collections.
public class MyDictionary:Dictionary<Foo, int>
{
public Bar():base()
{
}
new public int this[string key]
{
get
{
return this[base.Keys.Single(a => a.Name == key)];
}
}
}
And then this code works well:
MyDictionary<Foo, int> dic = new MyDictionary<Foo, int>();
dic.Add(foo1, 1234);
dic.Add(foo2, 2345);
int i=dic["Foo1"];

C# - how to write a collection (Dictionary?) with one key and two values [duplicate]

This question already has answers here:
C# Dictionary with two Values per Key?
(10 answers)
Closed 6 years ago.
What's the easiest way to create a collection of key, value1, value2 ?
Important to me is that it is easy & short to retrieve either value1 or value2 given the pair (please show an example)
I know I can do this -
class MyObject
{
internal string NameA { get; set; }
internal string NameB { get; set; }
}
class Other
{
Dictionary<string, MyObject> MyObjectCollection { get; set; }
private void function()
{
MyObjectCollection = new Dictionary<string, MyObject>()
{ { "key", new MyObject { NameA = "something", NameB = "something else" } } };
var valueA = MyObjectCollection["key"].NameA; // = "something"
}
}
Is there a better way?
The solution which is easiest to implement (Dictionary<String, Tuple<String, String>>) is not the one which is easiest to support and develop (what is MyObjectCollection[key].Value2?). So I suggest using your own class:
class MyPair {
public string NameA { get; internal set; }
public string NameB { get; internal set; }
public MyPair(nameA, nameB) {
NameA = nameA;
NameB = nameB;
}
public override String ToString() {
return $"NameA = {NameA}; NameB = {NameB}";
}
}
class Other {
// you don't want "set" here
// = new ... <- C# 6.0 feature
public Dictionary<string, MyPair> Data { get; } = new Dictionary<string, MyPair>() {
{"key", new MyPair("something", "something else")},
};
...
Other myOther = new Other();
String test = myOther.Data["key"].NameA;
You can use a Tuple:
Dictionary<string,Tuple<string,string>> MyObjectCollection {get; set;}
private void function()
{
MyObjectCollection = new Dictionary<string, Tuple<string,string>>();
MyObjectCollection.Add("key1", Tuple.Create("test1", "test2"));
}
List<MyObject> list = new List<MyObject>();
var res = list.ToDictionary(x => x, x => string.Format("Val: {0}", x));
The first lambda lets you pick the key, the second one picks the value.

Create a dictionary of a model?

It's quite hard for me to explain this, but I will give it a go.
Objective:
Create a LINQ query that will return a dictionary of data. However it must be a dictionary of the model which I am using.
View Model:
public class ValueBySupplierAndClaimTypeViewModel : ReportViewModel
{
public IQueryable<ValueBySupplierAndClaimTypeModel> ReportData {get; set; }
public TotalValueBySupplierAndClaimTypeModel ReportTotalData { get; set; }
public Dictionary<string, decimal> DictionaryData { get; set; }
public string output { get; set; }
}
Interface:
Dictionary<string, decimal> DictData;
TotalValueBySupplierAndClaimTypeModel GetTotalValueBySupplierAndClaimType(
int ClientID, int ReviewPeriodID, int StatusCategoryID);
SQL Repository:
public TotalValueBySupplierAndClaimTypeModel GetTotalValueBySupplierAndClaimType(int ClientID, int ReviewPeriodID, int StatusCategoryID)
{
var rt =
this.GetValueBySupplierAndClaimType(ClientID, ReviewPeriodID, StatusCategoryID);
TotalValueBySupplierAndClaimTypeModel x = new TotalValueBySupplierAndClaimTypeModel()
{
NormalTotal = rt.Sum(c=>c.Normal) ?? 0,
QueryTotal = rt.Sum( c => c.Query) ?? 0,
StrongTotal = rt.Sum( c => c.Strong) ?? 0
};
return x;
}
I'm really not sure how to do this. Can anybody help?
I have this function that converts an object to a dictionary. It gets all the properties of the class, as the dictionary's keys. May be you can modify it to meet your needs:
public Dictionary<string, object> ConvertClassToDict(object classToConvert)
{
Dictionary<string, object> result = new Dictionary<string, object>();
PropertyInfo[] properties = classToConvert.GetType().GetProperties();
List<string> propertiesNames = properties.Select(p => p.Name).ToList();
foreach (var propName in propertiesNames)
{
PropertyInfo property = properties.First(srcProp => srcProp.Name == propName);
var value = property.GetValue(classToConvert, null);
result.Add(propName, value);
}
return result;
}
The argument classToConvert, is just an instance of any class.
Similar to #lukiller's answer, but with LINQ:
public Dictionary<string, object> MapToDictionary(object instance)
{
if(instance == null) return null;
return instance.GetType()
.GetProperties()
.ToDictionary(p => p.Name,
p => p.GetValue(instance));
}
For example, let's suppose we have the following class:
public class User
{
public string Username { get; set; }
public string Password { get; set; }
}
We can print it like this (one line):
MapToDictionary(new User()
{
Username = "mcicero",
Password = "abc123"
}).ToList().ForEach(i => Console.WriteLine("{0}: {1}", i.Key, i.Value));
This prints out:
Username: mcicero
Password: abc123

How to compare all values in an object without repeating if statements?

I am trying to compare all possible values in a list of objects like this:
public class Object21
{
int Id,
bool firstbool,
bool secondbool
}
I would loop through the objects and compare them like this:
List<Object1> objects;
foreach(var o in objects)
{
if(firstbool && secondbool)
....
if(firstbool && !secondbool)
....
if(!firstbool && secondbool)
....
if(!firstbool && !secondbool)
....
}
This seems ok, but what if the object had several values that you were running through if statements.
public class Object2
{
int Id;
int firstbool;
....
int twentiethbool;
}
Then you would have to write out all of the possible conditional statements and your code would be terribly written and hard to read.
List<Object2> objects2;
foreach(var o in objects2)
{
if(firstbool && secondbool && ... && twentiethbool)
....
if(....)
....
....
....
if(!firstbool && !secondbool && ... && !twentiethbool)
....
}
Is there a simpler way to write the second scenario so that you are not writing every combination of if statements?
In the end I would like to calculate the percentage occurrence of each condition in the list.
To answer the first part of the question (about comparing every combination):
There isn't really a good way to do that, other than write a bunch of if statements. Of course; you probably shouldn't be doing that anyways :)
You could probably use reflection and recursion, but thats going to get messy really fast.
Luckily, to just get the percentage occurrence of each flag, you can just do:
list.Count(i => i.firstbool) / (double)list.Count();
...
first, create a dictionary to save all conditions
var dict = new Dictionary<string, int>{{"001",0},{"010",0} ...}
then, create key use bool values
var key=string.Empty;
key+=firstbool ?"0":"1"
key+=secondbool ?"0":"1"
......
after all, you can know which condition occurred
dict[key]++;
Given a class structure like this:
public class YourClass
{
public int Id { get; set; }
public bool firstbool { get; set; }
public bool secondbool { get; set; }
public bool thirdbool { get; set; }
}
You can use reflection to get all the boolean values (and only bool values) inside the class:
public IEnumerable<bool> GetBools(YourClass obj)
{
return obj.GetType()
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(x => x.PropertyType == typeof (bool))
.Select(x => (bool)x.GetValue(obj, null));
}
Then use LINQ to iterate through the collection, and create a dictionary of combinations and totals:
List<YourClass> objects = new List<YourClass>();
var totals = objects.GroupBy(x => String.Join(",", GetBools(x)))
.ToDictionary(x => x.Key, x => x.Count() / (double)objects.Count);
This will give you a dictionary with each unique combination and the percentage it occurs.
Given this input:
var o = new List<YourClass>
{
new YourClass {firstbool = true, secondbool = true, thirdbool = false},
new YourClass {firstbool = false, secondbool = false, thirdbool = false},
new YourClass {firstbool = true, secondbool = true, thirdbool = false}
};
The result in the dictionary will be:
{["True,True,False", 0.666666666666667]}
{["False,False,False", 0.333333333333333]}
it's probably easier to rewrite your class, storing each condition in an array like follows:
public class MyObject
{
public static int numFields = 20;
public enum Conditions
{
C1, C2, C3, .... C20 //name for each condition, so can set values using descriptive names
};
public Boolean[] BinaryFields = new Boolean[numFields];
public void setCondition(Conditions condition, Boolean value)
{
BinaryFields[(int)condition] = value;
}
public override string ToString()
{
return string.Join(",", BinaryFields);
}
}
then you can calculate the stat by counting what is actually there, instead of numerating through all of the 2^20 possibilities. something like follows:
static void Main(string[] args)
{
//simulation: creat 10 MyObjects
List<MyObject> lst = new List<MyObject>();
for (int i = 0; i < 10; i++)
{
MyObject m = new MyObject();
//example of setting condition
m.setCondition(MyObject.Conditions.C1, true);
lst.Add(m);
}
//calculate stat
var resultCount = new Dictionary<string, int>(); //conditionResult, count
foreach (MyObject m in lst)
{
if (resultCount.ContainsKey(m.ToString()))
{
resultCount[m.ToString()] += 1;
}
else
{
resultCount.Add(m.ToString(), 1);
}
}
//print stat
foreach(KeyValuePair<string, int> entry in resultCount){
Debug.WriteLine("probability for conditoin={0} is {1}", entry.Key, (double)entry.Value / lst.Count);
}
}
If you have some unique action for each boolean properties combination I suggest you to use some kind of string key for your object, generated on those values. Something like "001001", "000000" etc. Then use Dictionary<string, Func<int>> to hold all your unique actions, get and perform the right one by it's key. For example:
public class Object21
{
public int Id { get; set; }
public bool FirstBool { get; set; }
public bool SecondBool { get; set; }
public bool ThirdBool { get; set; }
public bool FourthBool { get; set; }
public bool FifthBool { get; set; }
public bool SixthBool { get; set; }
public void Process()
{
// Perform the action
Actions[Key]();
}
// Returns "001001" like representation of your object
public string Key
{
get
{
return string.Join(string.Empty, GetType()
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(x => x.PropertyType == typeof(bool))
.Select(x => (bool)x.GetValue(this, null) ? "1" : "0" ));
}
}
private static Dictionary<string, Func<int>> Actions
{
get
{
return new Dictionary<string, Func<int>>
{
{"000000", new Func<int>(delegate
{
Console.WriteLine("000000 action performed.");
return 0;
})},
{"000001", new Func<int>(delegate
{
Console.WriteLine("000001 action performed.");
return 1;
})},
{"000010", new Func<int>(delegate
{
Console.WriteLine("000010 action performed.");
return 2;
})},
// More actions
{"111111", new Func<int>(delegate
{
Console.WriteLine("111111 action performed.");
return 63;
})}
};
}
}
}
And then use this in your program like this:
static void Main(string[] args)
{
var list = new List<Object21>
{
// initialize your list
};
foreach (var object21 in list)
{
object21.Process();
}
// Calculate your occurrences (basically what #Grant Winney suggested)
var occurrences = list.GroupBy(o => o.Key).ToDictionary(g => g.Key, g => (g.Count() / (double)list.Count)*100);
foreach (var occurrence in occurrences)
{
Console.WriteLine("{0}: {1}%", occurrence.Key, occurrence.Value);
}
}

Categories