C# multi-dimensional array, ArrayList, or hash table? - c#

I'm trying to figure out how to build a multi-dimensional "array" that is:
flexible size
use 2 keys
1st key is int (flexible)
2nd key is string (kind of limited)
The use will be like:
console.writelen(array[0]["firstname"]);
console.writelen(array[0]["lastname"]);
console.writelen(array[0]["phone"]);
console.writelen(array[1]["firstname"]);
console.writelen(array[1]["lastname"]);
console.writelen(array[1]["phone"]);
.....
.....
console.writelen(array[x]["firstname"]);
console.writelen(array[x]["lastname"]);
console.writelen(array[x]["phone"]);

Are you sure it wouldn't be more appropriate to create a class/struct to contain the data? For example:
class Person
{
public string FirstName
{
get;
set;
}
public string LastName
{
get;
set;
}
public string Phone
{
get;
set;
}
}
Then you'd just create an array of Person:
var array = new Person[1];
array[0] = new Person() { FirstName = "Joe", LastName = "Smith", Phone = "foo" };
Or, since you say "flexible size", maybe you'd want a list instead:
var list = new List<Person>();
list.Add(new Person());
Update: The syntax used to set array[0] in the first example is an object initializer; the following two snippets are roughly equivalent:
var foo = new Person();
foo.FirstName = "John";
var bar = new Person() { FirstName = "John" };
So yes, you could just call list.Add(new Person() { ... }) if you wanted to. You could also make use of collection initializers in this case:
var john = new Person() { FirstName = "John" };
var joe = new Person() { FirstName = "Joe" };
var list = new List<Person>() { john, joe };

You can simply use this:
Dictionary<int, Dictionary<string, string>>
Use it like this:
var dd = new Dictionary<int, Dictionary<string, string>>();
dd[5] = new Dictionary<string, string>();
dd[5]["a"] = "foo";
You can also create a new class to simplify the creation of the inner dictionary:
class DDict { // optional: generic
private readonly Dictionary<int, Dictionary<string, string>> _Inner = new ...;
public Dictionary<string, string> this (int index) {
Dictionary<string, string> d;
if (!_Inner.TryGetValue(index, out d)) {
d = new Dictionary<string, string>();
_Inner.Add(index, d);
}
return d;
}
}
var dd = new DDict();
dd[5]["a"] = "hi";
If the first index is sequential, you can of course also just use an array of dictionaries:
var dd = new Dictionary<string, string>[128];
Also, if the inner members are always the same, I suggest to create a new class and access it in an array:
class Dat {
string name;
string phone;
}
var list = new Dat[128]
// access:
list[5].name = "matt";
Instead of an array, you could also use a List or a Dictionary<int, Dat> in that case.

I don't believe you can do this with an Array unless you have a single Array of KeyValuePair<int,string>, but I think you really want a Dictionary<int,string>.
var dic = new Dictionary<int,string>();
dic[0] = "zero";
dic[1] = "one";
dic[2] = "two";
foreach(KeyValuePair<int,string> kvp in dic)
{
Console.WriteLine(String.Format("Key: {0}, Value: {1}",kvp.Key,kvp.Value);
}

Actually i just see two dimensions. The first one is a row index, the second is a column index. And this sounds like a DataTable to me.

Related

Convert List to List<Dictionary> efficiently without foreach in c# [duplicate]

This question already has answers here:
How can I convert a class into Dictionary<string,string>?
(8 answers)
Closed 4 years ago.
Assume I have a list of class
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
Now i need to convert into List of Dictionary as
Assume it as List<Dictionary<key, value>>PersonDict, below is the structure of each indexes of the same. The key name should be dynamically populated as Property name in the class Person.
key : "Id", Value : Person.Id
key : "Name", Value : Person.Name
key : "Age", Value : Person.Age
Can anyone please help, I have already tried "for each" and "Parallel For each" loop but its taking lot of time, I have 3 millions of record to convert and its taking hours.
Here is a working implementation:
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
// Create some sample records
var persons = new List<Person>(){
new Person(){Id = 1, Name = "Bob", Age = 30},
new Person(){Id = 2, Name = "Jane", Age = 31},
new Person(){Id = 3, Name = "Mary", Age = 32}
};
// Use Reflection to retrieve public properties
var properties = typeof(Person).GetProperties();
// Create a list to store the dictionaries
var listOfDictionary = new List<Dictionary<string, string>>();
// For each person class
foreach(var person in persons){
// Create a new dictionary
var dict = new Dictionary<string,string>();
// For each property
foreach(var prop in properties){
// Add the name and value of the property to the dictionary
dict.Add(prop.Name, prop.GetValue(person).ToString());
}
// Add new dictionary to our list
listOfDictionary.Add(dict);
}
// Check the contents of our list
foreach(var dict in listOfDictionary){
Console.WriteLine(string.Join(",", dict.Keys));
Console.WriteLine(string.Join(",", dict.Values));
}
}
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
}
You mention that you have millions of records to convert. It may be not the best idea to create millions of Dictionary<> instances, nor to keep them all in memory. However, it is difficult to recommend something without knowing what is your end goal.
This is pretty much the same as the other answers here, but using a slightly more terse syntax. Just a matter of preference.
List<Person> persons = new List<Person> {
new Person { Id = 1, Name = "Sally", Age = 10 },
new Person { Id = 2, Name = "Bob", Age = 9 },
};
List<Dictionary<string, string>> listOfDictionaries =
persons
.Select(p => new Dictionary<string, string>
{
["Id"] = p.Id.ToString(),
["Name"] = p.Name,
["Age"] = p.Age.ToString(),
})
.ToList();

Create a subset of an object based off an array of property names

I have a class and an array of property names defined as follows:
public class Dog {
public string Name { get; set; }
public string Breed { get; set; }
public int Age { get; set; }
}
var desiredProperties = new [] {"Name", "Breed"};
I also have a method that returns a list of dog objects:
List<Dog> dogs = GetAllDogs();
Is there an way I can return a subset of dogs that only contain the properties defined within the desiredProperties array? Eventually, this resulting list will be serialized to JSON.
I have been struggling with this problem for some time now, considering that the user will be allowed to specify any combination of properties (assuming they are all valid) as the output within the array. Some more examples:
var desiredProperties = new [] {"Name", "Age"};
// Sample output, when serialized to JSON:
// [
// { Name: "Max", Age: 5 },
// { Name: "Spot", Age: 2 }
// ]
var desiredProperties = new [] {"Breed", "Age"};
// [
// { Breed: "Scottish Terrier", Age: 5 },
// { Breed: "Cairn Terrier", Age: 2 }
// ]
you can write a function to do that. Use the extension method below.
public static class Extensions
{
public static object GetPropertyValue(this object obj, string propertyName)
{
return obj.GetType().GetProperty(propertyName).GetValue(obj);
}
public static List<Dictionary<string, object>> FilterProperties<T>(this IEnumerable<T> input, IEnumerable<string> properties)
{
return input.Select(x =>
{
var d = new Dictionary<string, object>();
foreach (var p in properties)
{
d[p] = x.GetPropertyValue(p);
}
return d;
}).ToList();
}
}
Test it like
var dogs = GetAllDogs();
var f1 = dogs.FilterProperties(new[]
{
"Name", "Age"
});
var f2 = dogs.FilterProperties(new[]
{
"Breed", "Age"
});
Console.WriteLine(JsonConvert.SerializeObject(f1));
Console.WriteLine(JsonConvert.SerializeObject(f2));
and result is
[{"Name":"Spot","Age":2},{"Name":"Max","Age":5}]
[{"Breed":"Cairn Terrier","Age":2},{"Breed":"Scottish Terrier","Age":5}]
I don't have a clue if this is the most efficient way to do it, but it's a way of doing it:
var list = new List<Dog>();
list.Add(new Dog {Name = "Max", Breed = "Bull Terrier", Age = 5});
list.Add(new Dog {Name = "Woofie", Breed = "Collie", Age = 3});
var desiredProperties = new[] {"Name", "Breed"};
var exportDogs = new List<Dictionary<string, object>>();
foreach(var dog in list)
{
var exportDog = new Dictionary<string, object>();
foreach(var property in desiredProperties)
{
exportDog[property] = dog.GetType().GetProperty(property).GetValue(dog, null);
}
exportDogs.Add(exportDog);
}
var output = JsonConvert.SerializeObject(exportDogs);
The output will look like this:
[{"Name":"Max","Breed":"Bull Terrier"},{"Name":"Woofie","Breed":"Collie"}]
If, however, you don't need to dynamically access properties, it's a lot better to do something like this:
var output = list.Select(dog => new {dog.Name, dog.Breed});
Then just serialize the output.
something like this...not tested...
var desiredProperties = new [] {"Name", "Breed"};
var lst = (from asm in AppDomain.CurrentDomain.GetAssemblies()
from asmTyp in asm.GetTypes()
where typeof(dog).IsAssignableFrom(asmTyp) && desiredProperties.All(p=> PropertyExists(asmTyp, p))
select asmTyp).ToArray();
private bool PropertyExists(Type dogType, string name)
{
bool ret=true;
try{ dogType.GetProperty(name);}
catch{ret=false};
return ret;
}

how to change the value of dictionary using linq based on key?

I have a Dictionary which is of type,
Dictionary<string, string> newdictionary = new Dictionary<string, string>();
newdictionary.Add("12345", "chip1");
newdictionary.Add("23456", "chip2");
Now i have a List which is of type
internal class CustomSerial
{
public string SerialNo { get; set; }
public decimal ecoID { get; set; }
}
var customList = new List<CustomSerial>();
CustomSerial custObj1= new CustomSerial();
custObj1.ecoID =1;
custObj1.SerialNo = "12345";
customList.Add(custObj1);
CustomSerial custObj2 = new CustomSerial();
custObj2.ecoID = 2;
custObj2.SerialNo = "23456";
customList.Add(custObj2);
Now i need to update the Initial dictionary by Filtering the Keys with ther SerialNumber and Replacing the values with the ecoID.
When i try this, it gives
foreach (KeyValuePair<string, string> each in newdictionary)
{
each.Value = customList.Where(t => t.SerialNo == each.Key).Select(t => t.ecoID).ToString();
}
System.Collections.Generic.KeyValuePair.Value' cannot be assigned to -- it is read only
LIN(Q) is a tool to query something not to update it.
However, you can first query what you need to update. For example:
var toUpdate = customList
.Where(c => newdictionary.ContainsKey(c.SerialNo))
.Select(c => new KeyValuePair<string, string>(c.SerialNo, c.ecoID.ToString()));
foreach(var kv in toUpdate)
newdictionary[kv.Key] = kv.Value;
By the way, you get the "KeyValuePair.Value' cannot be assigned to it is read only" exception because aKeyValuePair<TKey, TValue> is a struct which cannot be modified.
You'd have the simplest in this form: though I don't see why you are assigning the same value but the method applies regardless
var dictionary = new Dictionary<string, string>() { { "12345", "chip1" }, { "23456", "chip2" } };
var customList = new List<CustomSerial>() { new CustomSerial() { ecoID = 1, SerialNo = "12345" }, new CustomSerial() { ecoID = 2, SerialNo = "23456" } };
dictionary.Keys.ToList().ForEach(key =>
{
dictionary[key] = customList.FirstOrDefault(c => c.SerialNo == key).SerialNo;
});

Mixing in new fields to an object without hard-coding its fields in a LINQ query?

I have a simple LINQ query here:
var Staffs = new[]
{
new { id = 1, name = "Jefferson", age = 42},
new { id = 2, name = "Jacobson", age = 54},
new { id = 3, name = "Zhang", age = 34}
};
var payroll = new[]
{
new { pid = 1, wage = 5000},
new { pid = 2, wage = 6500},
new { pid = 3, wage = 6700}
};
var q = from stf in Staffs
from pay in payroll
where stf.id == pay.pid
select new
{
stfObj = stf,
pay.pid,
pay.wage
};
Here, stfObj would be an object containing the id, name and age fields
Here comes the question:
Is it possible to turn the object into the fields themselves without explicitly hard-coding the field names like this:
select new
{
stf.id,
stf.name,
stf.age,
pay.pid,
pay.wage
};
In this way, there will be no need to change the select new block when I add a new field to Staffs, like Gender for example
Is that possible?
(ok, this looks like the question here... anyway, hoping to get better answers here)
Is this what you want!
select new
{
sId=stfObj.id,
sName=stfObj.name,
sAge=stdObj.age,
pId=pay.pid,
pWage=pay.wage
};
Why not simply embed your object ?
select new {
staff = stf,
pay = pay
};
I do not know, what you need this for. But you could try to use Dictionary<> for this. Say, we have a class:
public class Test
{
public string Name { get; set; }
public string Desc { get; set; }
}
So you can do the following:
List<Test> list = new List<Test>
{
new Test
{
Name = "Test 1",
Desc = "Desc 1"
}
};
var temp = list.Select(t =>
{
Dictionary<string, object> values = new Dictionary<string, object>();
foreach (PropertyInfo pi in t.GetType().GetProperties())
values[pi.Name] = pi.GetValue(t, null);
return values;
})
.FirstOrDefault();
temp.ToList().ForEach(p => Console.WriteLine(string.Format("{0}:\t{1}", p.Key, p.Value)));
So if you add a property to the Test class, say, like this:
public bool Extra { get; set; }
You'll get it in the dictionary automatically. Probably you'll have to work with reflection methods overloads to get exactly what you need...

convert string data array to list

i have an string data array which contains data like this
5~kiran
2~ram
1~arun
6~rohan
now a method returns an value like string [] data
public string [] names()
{
return data.Toarray()
}
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
List<Person> persons = new List<Person>();
string [] names = names();
now i need to copy all the data from an string array to an list
and finally bind to grid view
gridview.datasoutrce= persons
how can i do it. is there any built in method to do it
thanks in advance
prince
Something like this:
var persons = (from n in names()
let s = n.split('~')
select new Person { Name=s[1], Age=int.Parse(s[0]) }
).ToList();
var persons = names.Select(n => n.Split('~'))
.Select(a => new Person { Age=int.Parse(a[0]), Name=a[1] })
.ToList();
Assuming that the source data are completely valid (i.e. no negative ages, names do not contain '~', every line has both age and name, and so on), here's a very easy implementation:
List<Person> persons = new List<Person>;
foreach (var s in names()) {
var split = s.Split('~');
int age = int.Parse (split[0]);
string name = split[1];
var p = new Person() { Age = age, Name = name };
persons.Add (p);
}
You can also use a Linq query, which is shorter. See Marcelo's Answer for an example.

Categories

Resources