What is the best method to create an array or a list which contain a string and a number?
With Dictionary it can be done this way:
Dictionary < string, int > dict = new Dictionary < string, int > ();
but are there better methods with Array or List?
I need it to store IP addresses and coresponding port numbers.
The best way depends on your use case. But here's an easy way.
var list = new List<Tuple<string, int>> {
Tuple.Create("foo", 123),
Tuple.Create("bar", 234),
};
If you want a list of correlated ip addresses and ports, I'd make a dedicated type for it.
struct Address {
public string Ip;
public int Port;
}
...
var list = new List<Address>();
Due to the hashtable it is built upon; a Dictionary is the faster way to go if you are going to search the content to find a certain key.
var list = new Dictionary<string, int>();
A List of Key/Value pairs would need to parse each entry, every single "KeyValuePair" that is, to check if it contains a specific key. This will lead to an slightly exponentional performance loss upon adding more and more entries.
var list = new List<KeyValuePair<string, int>>();
Related
I want to create a Dictionary that have a multiple keys and when I want to get value using just one or more keys.
I tried :
Dictionary<Tuple<int, string>, string> dictionary = new Dictionary<Tuple<int, string>, string>();
var Key =new Tuple<int,string>(1,"I1");
var Value = "this is a value";
dictionary.Add(Key, Value);
When I try to get value from the dictionary I Must / Should enter all the keys
Like this :
MessageBox.Show($"{dictionary[new Tuple<int, string>(1,"I1")]}");
But when I try to get value using just one of keys like this
MessageBox.Show($"{dictionary[new Tuple<int, string>(1,"")]}");
I got error, I know that this error happened cause dictionary need the full exist key to return a value.
So please anyone have any Idea about how can I create a Dictionary with multiple keys and when retrieving value using just one or more or all keys ?
Dictionaries in .NET are expected to have close to O(1) lookup times. To achieve this, they make use of the GetHashCode() and Equals() methods of the key objects. The resulting hash code is used to divide the dictionary's contents into partitions. When you look up an item, the partition is identified using the hash code, all the items in that partition with a matching hash code* are compared to the key you're looking up using the Equals() method.
Here you are trying to create a dictionary with two keys for every object. You're doing this using a Tuple to make one key. The GetHashCode() result of a Tuple is based on both of its values, so the performance of a dictionary is lost if you want to look up values by only half of the key. You would need to go through the entire dictionary comparing each individual item, rendering it little better than a list.
One solution would be to make a dictionary that has a string->int key lookup, and then the other dictionary just be int->string. This would require two lookups when using string keys, but might be a good solution.
Example:
Dictionary<string, int> stringKeyToIntKey = new Dictionary<string, int>();
Dictionary<int, string> intKeyDict = new Dictionary<int, string>();
intKeyDict[1] = "Test";
stringKeyToIntKey["I1"] = 1;
Console.WriteLine(intKeyDict[1]);
Console.WriteLine(intKeyDict[stringKeyToIntKey["I1"]]);
An add method could look like this:
public void AddEntry(int intKey, string stringKey, string value)
{
intKeyDict[intKey] = value;
stringKeyToIntKey[stringKey] = intKey;
}
And you could wrap TryGetValue to make life easier:
public bool TryGetValue(string stringKey, out string value)
{
value = null;
return stringKeyToIntKey.TryGetValue(stringKey, out int intKey) && intKeyDict.TryGetValue(intKey, out value);
}
Delete would look like this:
public void DeleteEntry(string stringKey)
{
if (stringKeyToIntKey.TryGetValue(stringKey, out int intKey))
{
intKeyDict.Remove(intKey);
stringKeyToIntKey.Remove(stringKey);
}
}
You would have to make sure that items are added and removed from both dictionaries at the same time. When you add an item to intKey, you would need to add the corresponding key mapping to stringKeyToIntKey.
Alternatively, you could have two dictionaries: one with a string key and one with an int key, and each would have the same values. Again you would have to add and remove items at the same time, and you would also have to update the values in both at the same time.
Example:
Dictionary<string, string> stringKeyDict = new Dictionary<string, string>();
Dictionary<int, string> intKeyDict = new Dictionary<int, string>();
stringKeyDict["I1"] = "hello";
intKeyDict[1] = "hello";
Console.WriteLine(stringKeyDict["I1"]);
Console.WriteLine(intKeyDict[1]);
This is my favoured approach where the values are class instances, since both dictionaries will reference the same class instances for my items, and thus changes to properties of those instances will be reflected in both. For strings, however, the first option might be better.
* Hash codes are not unique and multiple objects can potentially have the same hash code, even if their values are not the same
You can use string for dictionary keys. Let's say you want to create a key from int x = 5 and string y = "str". You can concat and split them with some separator, and create a key like this:
string key = $"{x}:{y}"
And let's say you want to get elements only by x. you can write something like this:
dictionary.Where(kvp=>kvp.Key.Contains($"{x}:"))
of course, it will not give elements in O(1) time(it will give you elements in O(n) time) but it will work. If you want to get elements in O(1) time only by x I am not sure if it's possible with one dictionary.
I am trying to create a good way to store 3 variables, two ints and a point in C# programming.
I thought of a way by using an array of dictionaries
Dictionary<int, Point>[] ItemList = new Dictionary<int, Point>[4];
The Idea was that one variable has to be between 1 and 4, so I would have that as the sorting point, or each array location. The 2nd int, has to be between 0 and 15, and the point is on a 4x4 grid. I thought this method would work, and it would have except that You can't have the same key in a dictionary, and since both ints will be repeated, I can't swap them out. This idea also went out the window, same problem
Dictionary<int, int>[,] ItemList = new Dictionary<int, int>[4,4];
I also thought of using a tuple, and I don't have much(any) experience with it, and my experiments with them weren't going so well. The problem with it was I couldn't get the count of how many items were in it. I set one up like this.
Tuple<int, Point>[] ItemList = new Tuple<int, Point>[4];
Same Idea as my first example, Its just there is no code like this
ItemList[1].Count /*OR*/ ItemList[1].Length
Please let me know if I am missing something terribly obvious with tuples, or suggest an different storage method that would be nice to have all 3 variables stored all together.
You can use the Tuple to store directly the 3 data structures. A Tuple can have more than two items, and of any type. That way, you don't have to use your array:
Tuple<int, int, Point>
To get the values, use the corresponding Item property. For the first int, it will be yourTuple.Item1. For the second one yourTuple.Item2 and for the Point yourTuple.Item3.
If you have multiple Tuples, you can use a classic List to store them all:
var tuples = new List<Tuple<int, int, Point>>();
Since it's a list, you can get the count easily: tuples.Count()
So a class seems like the proper structure to me.
public class Something {
public int Item1 { get; set; }
public int Item2 { get; set; }
public Point Location { get; set; }
}
Then you store these objects in a List<>
var List<Something> list = new List<Something>();
add items to the list...
list.Add(new Something() {Item1 = 4, Item2 = 8, Point = new Point(x,y)});
then use some LINQ to get just the ones you want.
var onlyItem1IsFour = (from item in list where 4 == item.Item1 select item).ToList();
excuse my LINQ. I'm used to VB and may have gotten the casing/syntax slightly wrong
Well, Using the idea of using a list, I solved my problem. Its kinda a hybrid between the suggested ideas and my original idea with using the array. You don't have to use an array if you are looking to do something similar, you can use a tuple with 3 values, I just needed an array for one int value because I needed them stored separately, based off of what that one int value was (between 0 and 4). Here is some code that would work.
List<Tuple<int, Point>>[] ItemList = new List<Tuple<int, Point>>[4]; // how to declare it
for (int i = 0; i < 4; i++)
{
ItemList[i] = new List<Tuple<int, Point>>(); // initilize each list
}
ItemList[1].Add(new Tuple<int, Point>(5, new Point(1, 2))); // add a new tuple to a specific array level
int count = ItemList[1].Count; // finds the count for a specific level of the array --> (1)
int getInt = ItemList[1].ElementAt(0).Item1; // finds int value --> (5)
Point getPoint = ItemList[1].ElementAt(0).Item2; // finds the point --> (1,2)
What I need is something like an array but letting me to assign an element to whatever an index at any time and check if there is already a value assigned to particular index approximately like
MyArray<string> a = new MyArray<string>();
a[10] = "ten";
bool isTheFifthElementDefined = a[5] != null; // false
Perhaps Dictionary<int, string> with its ContainsKey method could do, but isn't there a more appropriate data structure if I want an ordered collection with numeric keys only?
I am also going to need to iterate through the defined elements (with foreach or linq preferably) accessing both the value and the key of current element.
As you mentioned Dictionary seems more appropriate for this.But you can do it with generic lists,for example, when you are creating your list you can specify an element count,and you can give a default temporary value for all your elements.
List<string> myList = new List<string>(Enumerable.Repeat("",5000));
myList[2300] = "bla bla bla..";
For int:
List<int> myList = new List<int>(Enumerable.Repeat(0,5000));
For custom type:
List<MyClass> myList = new List<MyClass>(Enumerable.Repeat(new MyClass(), 100));
Ofcourse It is not the best solution...
Note: Also you can use SortedList instead of Dictionary if you want an ordered collection by keys:
SortedList<TKey, TValue> : Represents a collection of key/value pairs that are sorted by key based on the associated IComparer implementation.
If you need key/value pairs you cannot use a list, you'll need a Dictionary.
The implementation is pretty snappy so don't be too afraid about performance (as long as you don't put too much values in it).
You can iterate over it with
foreach(KeyValuePair<int, string> kvp in dict)
{
}
If you need to order it you can use a list:
List<int> ordered = new List(dict.Keys);
ordered.Sort();
foreach(int key in ordered)
{
}
I am using C#.
I've created 2 arraylists called Names and Performances and the data in them are filled from my database.
I wanna create an arraylist or something like an array of 2 dimensions so
array[Name][Performance].
array[0][0] => should give me first persons first performance data
array[0][1] => should give me firstpersons second performance data
array[0][2] => should give me first persons third performance data...
The size of Names and Performance are changeable due to diffrent sql queries.
since sizes are changeable i tried to use loops and size of Name and Performance arraylists in those loops. How can i handle that collection to hold both of my arraylists?
Why don't you use a generic List ?
You can then for instance create a type which holds the Person and his performance data, like this:
class PersonPerformance
{
public string Name { get; set; }
public List<Performance> Performances { get; set; }
}
And you create a collection easily:
var performances = new List<PersonPerformance>();
You can use something like that
IList<KeyValuePair<string, string>> innerList = new List<KeyValuePair<string, string>>();
IList<IList<KeyValuePair<String,string>>> list=new List<IList<KeyValuePair<string, string>>>();
list.Add(innerList);
Where KeyValuePair contains Name and Perfomance element
I assume your Names are of the type string.
I usually do (if I don't have set size)
List<KeyValuePair<string, TYPE_X>> list = new List<KeyValuePair<string, TYPE_X>>();
or (the size is known)
KeyValuePair<string, TYPE_X>[] array = new KeyValuePair<string, TYPE_X>[size];
or better
public Dictionary<string, TYPE_X> dict = new Dictionary<string, TYPE>();
if names are unique and I want to acces them like that (not in order):
TYPE_X object = dict["myName"];
You can use Use Dictionary<Name,List<Performance>> Type
hence for each name you get the set of Performances
I have a text file with the following structure
01|value|value|value|value|value|value
02|value|value|value|value|value|value
03A|value|value|value|value|value|value
03A|value|value|value|value|value|value
.
.
N
04|value|value|value|value|value|value
05|value|value|value|value|value|value
06|value|value|value|value|value|value
.
.
N (variable lines)
I tried to read the text file and add it to a dictionary of type <string, string[]> in order to use it like MyDic["01"][0], this is a fragment of the code:
Dictionary<string, string[]> txtFromFile= new Dictionary<string, string[]>();
string strLine;
using (StreamReader sr = new StreamReader(filePath))
{
while ((strLine= sr.ReadLine()) != null)
{
string[] strNodes= strLine.Split('|');
txtFromFile.Add(strNodes[0], strNodes);
}
}
Unfortunately, as you can see, this text file could have duplicated keys like 03A, so I was wondering if there's a collection in c# to achieve this.
NOTE I saw a class named lookup, but there's no constructor for it.
Any thoughts my friends?
What do you suggest?
Thanks!
Why not just create a class like
public class MyLine
{
string key { get;set;}
string[] value {get;set;}
}
and store it in a geneirc List
then you can use linq to query whatever you want ...
You can use the ToLookup extension method:
string[] lines = File.ReadAllLines(filePath);
ILookup<string, string[]> result = lines
.Select(line => line.Split('|'))
.ToLookup(parts => parts[0]);
The first problem is that you are trying to use the wrong type, if you are concerned with multiple entries with the same key. You can achieve this with a List<KeyValuePair<string, string[]>> and your own lookup function, likely through extending the class, or you can add another dictionary inside the dictionary as your value type: Dictionary<string, Dictionary<int, string[]>>. The Dictionary option is the better bet as it has better performance.
How about a List with a custom type?
class KeyValue
{
String ID { get ; set ; }
List<String> Values { get ; private set ;}
(..Constructor etc...)
}
List<KeyValue> myValues = new List<KeyValue>();
while ((strLine= sr.ReadLine()) != null)
{
string[] strNodes= strLine.Split('|');
myValues.Add(new KeyValue(strNodes[0],strNodes));
}
You could use List<KeyValuePair<string, string[]>> or List<Tuple<string, string[]>>
(And of course you might prefer a different collection type instead of List<>)
I'm not sure if you're trying to distinguish between values on the first 03A line from values on the second 03A line, but I think you're looking for a NameValueCollection. NameValueCollections allow you to add multiple values to the same key, and the Add() method should check for pre-existing keys before appending the values/creating a new key/value entry.
There's a good example of the way to use the NameValueCollection at the bottom of that MSDN reference article, so you should be able to use that to determine if it's what you really need.
Another thought would be to use
Dictionary<string, List<string[]>>
Where "string" is the value that might be repeated. When it gets repeated, you create another Dictionary inside. If a row exists once, it will have one List. If a duplicate row is found, add another. In this way, you can see how many duplicate rows there were just by count of Lists.