I am unsure whether this is possible with an ArrayList or a Dictionary or whether it would be something else, if so I wonder where you could point me in the right direction...
Can you have an ArrayList with Multiple Values i.e.
ArrayList weather = new ArrayList();
weather.Add("Sunny", "img/sunny.jpg");
weather.Add("Rain", "img/Rain.jpg);
To then assign to controls like below.
if (WeatherValue = 0)
{
Label1.Text = weather[0].ToString;
Image1.ImageUrl = weather[0].ToString;
}
Or can I do this with a Dictionary
Dictionary<string, string> dict = new Dictionary<string, string>();
dict.Add("Cloudy", "../img/icons/w0.png"); //[0]
dict.Add("Rain", "../img/icons/w1.png"); //[1]
Label1.Text = dict[0].VALUE1; //So this would get Cloudy
Image.ImageUrl = dict[0].VALUE2; //This would get ../img/w0.png
How do you call the values of a dictionary separately using [0], and [1] ? etc
There's no reason to still use ArrayList, use the System.Collections.Generic.List<T>-class. Then you keep compile time safety and you don't need to cast everything.
In this case you should create a custom class:
public class Weather
{
public double Degree { get; set; }
public string Name { get; set; }
public string IconPath { get; set; }
public override string ToString()
{
return Name;
}
}
Then you can use this readable and maintainable code:
List<Weather> weatherList = new List<Weather>();
weatherList.Add(new Weather { Name = "Sunny", IconPath = "img/sunny.jpg" });
weatherList.Add(new Weather { Name = "Rain", IconPath = "img/Rain.jpg" });
if (WeatherValue == 0) // whatever that is
{
Label1.Text = weatherList[0].Name;
Image1.ImageUrl = weatherList[0].IconPath;
}
Update: according to your edited question. A dictionary doesn't make much sense because you can't access it via index(it has no order) but only via key. Since that would be the weather-name you have to know it beforehand. But it seems that you don't have it.
So either loop all key-value pairs in the dictionary and use the key for the name and the value for the path or simply use a real class which would be much better.
If you don't want to create a class there's only one thing that comes to my mind, the Tuple:
List<Tuple<string, string>> weatherList = new List<string, string>();
weatherList.Add(Tuple.Create("Sunny", "img/sunny.jpg"));
weatherList.Add(Tuple.Create("Rain", "img/Rain.jpg"));
if (WeatherValue == 0) // whatever that is
{
Label1.Text = weatherList[0].Item1;
Image1.ImageUrl = weatherList[0].Item2;
}
You can use a Dictionary
Dictionary<string, string> weather = new Dictionary<string, string>();
values.Add("Sunny", "img/sunny.jpg");
values.Add("Rain", "img/Rain.jpg");
The simplest way to call element in a dictionnary is using foreach loop
foreach (var pair in weather )
{
Console.WriteLine("{0}, {1}",pair.Key,pair.Value);
}
Related
I need a class that can work with string properties to store data on a structured (class) list but at the same type to have a way to return an index that acts as the order I need to set up my data.
the class can be something like:
public class MyClass
{
public int int1 = 0;
public int int2 = 0;
public int int3 = 0;
public int int4 = 0;
public string string1 { get; set; }
public string string2 { get; set; }
public string string3 { get; set; }
public string string4 { get; set; }
}
then I can use my class to store the data in the class structured format:
string fileName = #"C:\Mylocation\MyTextFileToRead.txt"; //tab delimeted file
Encoding fileEncoding = Encoding.ASCII;
List<MyClass> myDataList = new List<MyClass>();
List<string> simpleData = File.ReadAllLines(fileName, fileEncoding).ToList();
MyClass index = new MyClass();
foreach (var line in simpleData)
{
var lineSplit = line.Split('\t');
MyClass myClassElement = new MyClass
{
string1 = lineSplit[index.int1],
string2 = lineSplit[index.int2],
string3 = lineSplit[index.int3],
string4 = lineSplit[index.int4],
};
myDataList.Add(myClassElement);
}
I use the index to map each property from the text file and then to store each filed values in the corresponding string property.
I do not wish to use object types and have the properties to return a string value and cast it as (int) for the index. I was advised not to use objects as much as possible.
The use of Const fields did not work for the index unless I use the type name of the class (instead an instance of the class), but I don't know if it helps or if this is a better programming option.
I'm not sure if there is a better way of doing this, but would be very welcome with relevant feedback.
To return two diffrent types from one function you can use the way that was introduce in C# 7.3
It works like this:
public (int, string) MyFunc()
{
//do something
return (VarThatInt, VarThatString);
}
//and in main class u call it like this:
(varInt, varString) = MyFunc();
using KeyValuePair to store one property and index, use list of KeyValuePair to store one line , and use dic Dictionary to store file .
List<int> orderIndexList = new List<int> { 2, 1, 4, 0 };
Dictionary<int, List<KeyValuePair<int, string>>> data = new Dictionary<int, List<KeyValuePair<int, string>>>();
int lineNumber = 0;
foreach (var line in simpleData)
{
var lineSplit = line.Split('\t');
List<KeyValuePair<int, string>> listLine = new List<KeyValuePair<int, string>>();
orderIndexList.ForEach(index => listLine.Add(new KeyValuePair<int, string>(index, lineSplit[index])));
data.Add(++lineNumber, listLine);
}
return data;
Return a class that has the two desired outputs. You can even return a third variable to tell the receiving code, which output to use.
public myClass{
String TextValue;
int NumberValue;
bool IsReturnString;
}
You would return an object of myClass.
I don't even know if I am on the right track but I gave a shot to Dictionary to store big and static data (like multi language data) and use it in the whole application. This example goes for a WinForms app.
In this scenario, I have a table which holds various parameters, divided into groups. The table is made of following fields: GROUP_CODE, PARAMETER_KEY, PARAMETER_VALUE... It simply holds lots of values as in this example:
GROUP_CODE: 'MAILING_INFO'
PARAMETER_KEY: 'SendMailAfterProcessIsDone'
PARAMETER_VALUE: 'a#b.com'
There is no problem or anything to hold and get the data from the database. My only problem is that how exactly I am going to handle this data...
My ParameterValues class holds the following, same fields I select from the table...
public class ParameterValues
{
private string groupCode;
private string parameterKey;
private string parameterValue;
public string GroupCode
{
get { return groupCode; }
set { groupCode = value; }
}
public string ParameterKey
{
get { return parameterKey; }
set { parameterKey = value; }
}
public string ParameterValue
{
get { return parameterValue; }
set { parameterValue = value; }
}
}
In another class, called CacheHelper, I am trying to put this object with the GROUP_CODE value as key into a Dictionary. (Hope that made sense)
public class CacheHelper
{
public Dictionary<string, ParameterValues> LoadParameterCache2()
{
//Dictionary<string, ParameterValues> objList = new Dictionary<string, ParameterValues>();
Dictionary<string, List<ParameterValues>> objList = new Dictionary<string, List<ParameterValues>>();
//call the values from the database blah blah
while (rdr.Read())
{
ParameterValues cacheObj = new ParameterValues();
cacheObj.ParameterKey = rdr.GetString("PARAMETER_KEY");
cacheObj.ParameterValue = rdr.GetString("PARAMETER_VALUE");
objList.Add(rdr.GetString("GROUP_CODE"), /*List ParameterValues goes here blah blah*/);
}
return objList; //and finally return it to the main application thread
}
}
I have to group it by GROUP_CODE values as from the database since Dic's "key" has to be unique... I know....
Since I think it was not clear enough, I tried to demonstrate what I am actually trying to do in the following image...
I simply cannot put it there groupped. Please someone show me a way... And also I'd like to hear your ideas if this is a good way to use this as application caching for really large data (thousands of rows I mean).
Many thanks!
I am not going to talk about caching solutions, as there are some out there and I am not particularly experienced with any.
But If you want to try static Dictionary solution, you could try grouping your data using Linq:
public Dictionary<string, List<ParameterValues>> LoadParameterCache2()
{
List<KeyValuePair<string, ParameterValues>> dataValues = new List<KeyValuePair<string, ParameterValues>>();
// Your code to produce the DataReader
DataTableReader rdr = GetDataReader();
while (rdr.Read())
{
ParameterValues cacheObj = new ParameterValues();
cacheObj.ParameterKey = (string)rdr["PARAMETER_KEY"];
cacheObj.ParameterValue = (string)rdr["PARAMETER_VALUE"];
KeyValuePair<string, ParameterValues> dataValue = new KeyValuePair<string, ParameterValues>((string)rdr["GROUP_CODE"], cacheObj);
dataValues.Add(dataValue);
}
Dictionary<string, List<ParameterValues>> objList = dataValues.GroupBy(d => d.Key).ToDictionary(k => k.Key, v => v.Select(i => i.Value).ToList());
return objList;
}
I think I get where you are having a problem, please note the syntax may be not 100% as I am typing from memory.
public class CacheHelper
{
public Dictionary<string, List<ParameterValues>> LoadParameterCache2()
{
var objList = new Dictionary<string, List<ParameterValues>>();
//call the values from the database blah blah
while (rdr.Read())
{
var cacheObj = new ParameterValues();
cacheObj.ParameterKey = rdr.GetString("PARAMETER_KEY");
cacheObj.ParameterValue = rdr.GetString("PARAMETER_VALUE");
//here is where you need to change things.
var groupCode = rdr.GetString("GROUP_CODE");
if (objList.ContainsKey(groupCode) == false)
{
objList.Add(groupCode, new List<ParameterValues> {cacheObj});
}
else
{
objList[groupCode].Add(cacheObj);
}
}
return objList; //and finally return it to the main application thread
}
}
Is there a List<> similar to a two dimension array? For each entry there is a number and text.
You can use Dictionary<int,String>
Sample:
Dictionary<int,string> samp = new Dictionary<int,string>();
dictionary.Add(1, "text1");
dictionary.Add(2, "text2");
Or, have a custom class which defines your requirement
public class Sample
{
public int Number;
public string Text;
}
Sample:
List<Sample> req = new List<Sample>();
Sample samObj = new Sample();
samObj.Number = 1;
samObj.Text = "FirstText";
req.Add(samObj);
There are many options, I describe some of them for you
use Dictionary<int, string>
Pros: very fast lookup
Cons: you can not have two string with same number, you don't have a List
var list2d = new Dictionary<int, string>();
list2d[1] = "hello";
list2d[2] = "world!";
foreach (var item in list2d)
{
Console.WriteLine(string.Format("{0}: {1}", item.Key, item.Value);
}
use Tuple<int, string>
Pros: very simple and handy tool, you have a List
Cons: Tuples are immutable, you can not change their values once you create them, reduces code readability (Item1, Item2)
var list2d = new List<Tuple<int, string>>();
list2d.Add(new Tuple(1, "hello"));
list2d.Add(Tuple.Create(1, "world");
foreach (var item in list2d)
{
Console.WriteLine(string.Format("{0}: {1}", item.Item1, item.Item2);
}
use a defined class,
Pros: you have a List, very customizable
Cons: you should write more code to setup
public class MyClass
{
public int Number { get; set; }
public string Text { get; set; }
}
var list2d = new List<MyClass>();
list2d.Add(new MyClass() { Number = 1, Text = "hello" });
list2d.Add(new MyClass { Number = 2, Text = "world" });
foreach (var item in list2d)
{
Console.WriteLine(string.Format("{0}: {1}", item.Number, item.Text);
}
Custom class or dictionary are good options, you can also use the Tuple generic...
var i = new List<Tuple<int, string>>();
Dictionary requires that whatever value is used as key must be unique. So not ideal without uniqueness.
A custom class is preferable if you don't mind a little more code and gives you scope to extend later on if you decide you want other data in there.
Tuple is quick and easy but you lose readability and objects can not be edited.
Define a class wih a string and an int property
public class MyClass
{
public string MyStr {get;set;}
public int MyInt {get;set;}
}
then create a list of this class
List<Myclass> myList = new List<MyClass>();
myList.add(new MyClass{MyStr = "this is a string", MyInt=5});
Hope it will help
public class DATA
{
public int number;
public string text;
}
List<DATA> list = new List<DATA>();
I have a listbox that prints the name of a custom item class
public class Item
{
public string #Url { get; set; }
public string Name { get; set; }
public double Price { get; set; }
public Item(string #url, string name, double price)
{
this.Url = url;
this.Name = name;
this.Price = price;
}
public override string ToString()
{
return this.Name;
}
}
I tried the normal method but because i have radio buttons to sort the list box it messes it up since index is changed.
EG
//new item is declared
Dictionary<int, Item> itemList = Dictionary<int, Item> { new Item("f.ca", "name1", 33);
new Item("m.ca", "name2", 44); }
//Items added to listbox
for (int v = 0; v < itemList.Count; v++)
{
itemListBox.Items.Add(itemList[v].Name);
}
//start sorting
var priceSort = from item in itemList
orderby item.Value.Price
select new { item.Value.Name, item.Value.Price };
itemListBox.Items.Clear();
foreach (var i in priceSort)
{
itemListBox.Items.Add(i.Name);
}
//end sorting listbox updated
now that the new list is created removing only the item in itemlist is necessary since the box is updated.
/* This code is what i thought but SelectedIndex say if on 0 and since the sorted by price */
itemList.Remove(itemListBox.SelectedIndex);
The issue being now its trying to remove items[0] when items[1] is really the one that needs to be removed. Is there a way i could make it compare the string of the itemlistbox to the .Name property of the items dictionary?
You stated that the key for your dictionary is determined by the current count of items in the dictionary. If that's the case, you'd have to do something like this:
var matches = itemList.Where(x => x.Name == itemListBox.SelectedValue);
if (matches.Any())
{
itemList.Remove(matches.First().Key);
}
But this is slow and inelegant. You're really not using the Dictionary class correctly. Dictionaries are ideal for performing quick access based on a known key value. If you have to search for the key every time, you loose all benefit the Dictionary provides.
You might as well use a simple List<Item> instead, using the FindIndex / RemoveAt methods:
var index = itemList.FindIndex(x => x.Name == itemListBox.SelectedValue);
if (index != -1)
{
itemList.RemoveAt(index);
}
This isn't a whole lot faster, but it's more elegant—lists are specifically designed to support this kind of thing without having to resort to Linq.
Or better yet, use the item's name as the dictionary key:
Dictionary<string, Item> itemList = Dictionary<string, Item>();
itemList.Add("name1", new Item("f.ca", "name1", 33));
itemList.Add("name2", new Item("m.ca", "name2", 44));
...
itemList.Remove(itemListBox.SelectedValue);
This is a much more efficient and elegant solution.
How can I store data from 2 columns (from a database) in a List
List<string> _items = new List<string>();
Any help is appreciated
You create a class that will represent a row with 2 columns:
public class Foo
{
// obviously you find meaningful names of the 2 properties
public string Column1 { get; set; }
public string Column2 { get; set; }
}
and then you store in a List<Foo>:
List<Foo> _items = new List<Foo>();
_items.Add(new Foo { Column1 = "bar", Column2 = "baz" });
Use a tuple struct like KeyValuePair
List<KeyValuePair<string, string>> _items = new List<KeyValuePair<string, string>>();
_items.Add(new KeyValuePair<string, string>(foo, bar));
I would use a class
List<MyDataClass> _items = new List<MyDataClass>();
public class MyDataClass
{
public string Value1 { get; set; }
public string Value2 { get; set; }
}
You can either create a new class to hold the data, Or you could use the built in Tuple<> class. http://msdn.microsoft.com/en-us/library/system.tuple.aspx
Also if one of the columns contains a unique ID of some sort, you could also consider using a Dictionary<>.
It's about how to retrieve the data from the new two columns list
List<ListTwoColumns> JobIDAndJobName = new List<ListTwoColumns>();
for (int index = 0; index < JobIDAndJobName.Count;index++)
{
ListTwoColumns List = JobIDAndJobName[index];
if (List.Text == this.cbJob.Text)
{
JobID = List.ID;
}
}
I know this question is pretty old and by now you probably got your answer and have figured out what you need but I wanted to add something that might help someone in the future.
The best current answer is frankly from #csharptest.net but it has a serious performance drawback and so here is my approach a la his answer based on a suggestion to use Dictionary<TKey, TValue>
private Dictionary<string, string> _items = new Dictionary<string, string>();
// if you need to check to see if it exists already or not
private void AddToList(string one, string two)
{
if (!_items.ContainsKey(one))
_items.Add(one, two);
}
// you can simplify the add further
private void AddToList(string one, string two)
{
_items[one] = two;
// note if you try to add and it exists, it will throw exception,
// so alternatively you can wrap it in try/catch - dealer's choice
}
you can also make array of list
List<string> [] list= new List<String> [];
list[0]=new List<string>();
list[1]=new List<string>();
list[0].add("hello");
list[1].add("world");
You could do this:
List<IList<string>> cols = new List<IList<string>>();
You can set how many columns you want.
cols.Add(new List<string> { "", "", "","more","more","more","more","..." });