I have dimensional list:
List<List<string>> index_en_bg = new List<List<string>>();
index_en_bg.Add(new List<string>() { word1, translation1 });
index_en_bg.Add(new List<string>() { word2, translation2 });
index_en_bg.Add(new List<string>() { word3, translation3 });
I would do binary search by the first column (words), something like this:
int row = index_en_bg.BinarySearch(searchingstr);
but it works only for a one-dimensional list. How would I extend it to work for two-dimensional lists in my case? I don't want to use Dictionary class.
In this case you need to provide your own customer IComparer-implementing comparator
public class Comparer: IComparer<IList<string>>
{
public int Compare(IList<string> x, IList<string> y)
{
// base the comparison result on the first element in the respective lists
// eg basically
return x[0].CompareTo(y[0]);
}
And you'll call it like this, offering a List where only the field you're searching is filled in.
int row = index_en_bg.BinarySearch(new List<string>() {searchingstr},new Comparer());
Well as far as I understand you should use Dictionary<K,V> instead, this way:
// 1 creating the dictionary
var dic = new Dictionary<string, string>();
dic["word1"] = "translation1";
dic["word2"] = "translation2";
dic["word3"] = "translation3";
// 2 finding a translation
var trans = dic["word1"];
And Dictionary<K,V> is really performant.
But if you insist on using BinarySearch you can implement IComparer<List<string>> and pass it to the function.
As you always search using the first item of the list you could use dictionary too.
var d = Dictionary<string, List<string>>();
as answered previously it's preforms much better than List.
Related
So I have a Dictionary with string keys, and the value is a List of objects. Each object in each List has a property value which is equal to that List's associated key. In other words, the Dictionary is grouping objects by property value via the key. For example, let's say we have,
Dictionary<string, List<Animal>> GroupedByClass = new Dictionary<string, Animal>();
Where Animal is an object which contains a string property named "ClassType" which has valid options of "Mammal", "Reptile", or "Amphibian", etc.
The Animal class could also have string property named "Species" which more uniquely defines each object in the Dictionary.
A pseudocode description of the contents of the Dictionary could be:
<"Mammal", List<Animal>>
where the Animals in the list have Species "Dog", "Cat"
<"Reptile", List>
where the Animals in the list have Species "Snake", "Lizard", and "Turtle"
<"Amphibian", List>
where the Animals in the list have Species "Salamander" and "Frog"
I want to rearrange this Dictionary by the key value such that the values with a key of "Reptile" are first, then "Amphibian", and then finally "Mammal". Note that I do not want to sort this based on alphabetical order, I want to specify my own order.
I know I could solve this problem by simply iterating through the Dictionary a few times, extracting only the items with the right key. For example, I could do it like this,
Dictionary<string, List<Animal>> temp = new Dictionary<string, List<Animal>>();
foreach(KeyValuePair<string, List<Animal>> item in GroupedByClass)
{
if(item.Key == "Reptile")
{
temp.Add(item.Key, item.Value);
}
}
foreach(KeyValuePair<string, List<Animal>> item in GroupedByClass)
{
if(item.Key == "Amphibian")
{
temp.Add(item.Key, item.Value);
}
}
foreach(KeyValuePair<string, List<Animal>> item in GroupedByClass)
{
if(item.Key == "Mammal")
{
temp.Add(item.Key, item.Value);
}
}
return temp;
However, this seems inelegant, and I was wondering if there was a better answer for this problem using Linq queries and lambda expressions.
This should be close (with some syntax errors):
var order = new [] {"Reptile","Amphibian","Mammal"};
var elems = dict.OrderBy(x=>order.IndexOf(x.Key));
if you want to flatten the results, then you can use SelectMany:
var order = new [] {"Reptile","Amphibian","Mammal"};
var elems = dict.SelectMany(x=>x).OrderBy(x=>order.IndexOf(x.Species));
Dictionary<string, List<Animal>> temp = new Dictionary<string,List<Animal>>();
(new List<string>() {"Reptile","Amphibian","Mammal"}).ForEach(x => temp.Add(x, GroupedByClass[x]));
You could define an enumeration and have it be your defining order.
enum Animal : int
{
Reptile = 0,
Amphibian = 1,
Mammal = 2
}
Note, since you have simple strings this works and is straight forward. If however you end up with strings that have spaces you can use the DescriptionAttribute of the enumeration and go between it and the actual enumeration.
Enumeration with Display String
By using an enumeration over the string you can do many things, but of course order by it using the integers you assiged.
i have two Dictionarys A & B, i want to see if all entries in A exist in B. In the past i've compared Lists using the following:
var set1 = new HashSet<String>(list1);
var set2 = new HashSet<String>(list2);
return set1.SetEquals(set2);
What i have thought to do is simply loop over each value in Dictionary A using:
dictA.TryGetValue(dictBvalue, out item)
this will return null on the item var if the value isn't there, but this seems a little long winded.
Is there a quick and effcient way of comparing dictionaries?
Thanks.
You could use All extension and do this.
var allexist = list1.All(x=> list2.ContainsKey(x.Key) && list2[x.Key] == x.Value)
here is the solution if you want to loop over each value
Dictionary<string, string> dictA = new Dictionary<string, string>();
Dictionary<string, string> dictB = new Dictionary<string, string>();
bool allexist = true;
foreach (var itemA in dictA)
{
if (!dictB.ContainsKey(itemA.Key))
{
allexist = false;
}
}
Actually, you asked for a method comparing dictionaries but your code example refer to HashSet which is different.
For HashSets, you can use IsSubsetOf and SetEquals methods.
To compare dictionaries, you can use DictionaryEquals method from this answer
I was asked this question today:
How can I add an item to a list and return that list back?
The code for List<T>.Add(T) returns void. So you can't do something like this:
var list = new List<string>{"item1","item2"};
var newList = list.Add("item3");
This is related to using AutoMapper, although that part isn't particularly important.
One option is Linq, with Concat:
var list = new List<string>{"item1", "item2"};
var newList = list.Concat(new[] { "item3" }).ToList();
In typical Linq fashion, list stays the same, and newList contains all the items from list as well as the items in the new list, in this case just "item3".
You can skip the .ToList() to keep the IEnumerable<string> result if that fits your use case.
If you find yourself doing this often with individual items, you can use something like this extension method to pass them without the new[] { ... } syntax:
public static IEnumerable<T> ConcatItems<T>(this IEnumerable<T> source, params T[] items)
{
return source.Concat(items);
}
Because of the params array the earlier example becomes:
var list = new List<string>{"item1", "item2"};
var newList = list.ConcatItems("item3").ToList();
Make sure not to mix this up with Union, which removes duplicate items. (Searching for those duplicates is overhead that you probably don't want!)
The answer to this question was relatively simple:
var list = new List<string>(new List<string>{"item1","item2"}){"item3"};
List<T>() has a constructor that can take in IEnumerable<T> (MSDN). Additionally, you can use the object setter to put new items into the list.
So, for a more complicated example:
var originalList = new List<string>();
originalList.Add("item1");
originalList.Add("item2");
var newList = new List<string>(originalList){"item3"};
You can simply do :
List<string> list = new List<string>{"item1","item2"};
List<string> newList = null;
(newList = list.ToList()).Add("item3");
Or create your own extension method :
public static class Helper
{
public static List<T> MyAdd<T>(this List<T> collection, T item)
{
collection.Add(item);
return collection;
}
}
And use it :
List<string> list = new List<string>{"item1","item2"};
List<string> newList = list.MyAdd("item3"); // same object though
List<string> newList2 = newList.ToList().MyAdd("item4").MyAdd("item5"); // different object
One property of an ImmutableList<T> (and other similar data structures from System.Collections.Immutable) is that it doesn't mutate the original list, it returns another immutable list with the added value.
So doing this:
var originalImmutable = ImmutableList<int>.Create(1, 2);
var otherImmutable = originalImmutable.Add(3);
Will result in a shallow copied new list each time you call Add.
The most readable and maintainable solution is to copy the list and then add the item:
var list = new List<string>{"item1","item2"};
var newList = list.toList();
newList.Add("item3");
Seven years have passed since the question has been asked but Enumerable class now offers Prepend and Append methods that could be used in a straightforward fashion:
var list = new List<string>{"item1","item2"};
var newList = list.Append("item3").ToList();
I am creating an array of string[] in my c# program to save location ("name","Position") of a bunch of elements. The problem is any time I had to introduce a new element I have to change the code at several places according to index of elements:
string[] list = new string[4];
list[0] = "[ELEMENT #1 NAME],[ELEMENT #1POSITION]";
list[1] = "[ELEMENT #2 NAME],[ELEMENT #2POSITION]";
list[2] = "[ELEMENT #3 NAME],[ELEMENT #3POSITION]";
list[3] = "[ELEMENT #4 NAME],[ELEMENT #4POSITION]";
What I am looking for is something like an dynamic array so that I do not have to change the index location every time I introduce/ remove an element from list.
You can use List<string> as a dynamic array, it supports IEnumerable<string> for enumerating, or you can call LINQ and ToArray().
For example:
var list = new List<string>();
list.Add("[ELEMENT #1 NAME],[ELEMENT #1POSITION]");
string array[] = list.ToArray();
However, I'd actually recommend a dictionary in this case and not a list, a dictionary will let you store key-value pairs.
For example:
var dict = new Dictionary<string,int>();
dict["Element #1 Name"] = #Element #1 Position#;
Note that I've no real idea what type the position is, could be an int, a string or even a Point, but you get the idea.
You then don't need to bother with indices but refer to everything by name:
var el1_pos = dict["Element #1 Name"];
var el999_pos = dict["Element #999 Name"];
You can use List<T> if you want a dynamically sized collection and don't bother with the index. And you should also create a type with two properties (Name and Position) and have a list of that type instead of storing them as string. It's easier to maintain, you don't have to parse the string every time you wanna get/set the Name or Position of a particular object.
Normally, you would just use a List<String> here. The Add method allows you to just add an element, no indexing required.
List<string> list = new List<string>();
list.Add("Test");
In your case, since you have "Name" and "Position" associated with each other, consider using a List<PositionedThing> (a custom class in other words) or a Dictionary<String, String> to store your mappings.
The class would look like:
public class PositionedThing
{
public String Name {get; set;}
public String Position {get; set;}
}
Try
List<string> list = new List<string>();
list.Add("[ELEMENT #1 NAME],[ELEMENT #1POSITION]")
Unless I've misunderstood your question that should be what you want
What I just want is to initialize a string[] array constant by specifying not only the values, but the indexes they will be attached to.
For example, on:
private static readonly string[] Pets = new string[] {"Bulldog", "GreyHound"};
I would like to state that BullDog corresponds to index 29 and GreyHound to 5 (Like php :) )
Any suggestion?
Cheers,
If you have some flexibility in terms of your data structure, it would be more efficient to use a Dictionary<int, string> instead of an array for this behavior.
Example (if you are using C# 3 or above):
var pets = new Dictionary<int, string> {
{ 29, "Bulldog" },
{ 5, "Greyhound" }
};
Console.WriteLine(pets[5]);
Same example for legacy applications:
Dictionary<int, string> pets = new Dictionary<int, string>();
pets[29] = "Bulldog";
pets[5] = "Greyhound";
Console.WriteLine(pets[5]);
It sounds like you don't want an array, but a Dictionary<int, string> instead, which could be initialized like this:
private static readonly Dictionary<int, string> pets =
new Dictionary<int, string> {
{ 29, "Bulldog" },
{ 5, "Greyhound" }
};
(Note that this collection initializer syntax was only added in C# 3. If you're using an older version you'll have to call Add or the indexer explicitly multiple times.)
You can access a dictionary via its indexer which looks like array access:
string x = pets[29];
pets[10] = "Goldfish";
I don't think what you want is possible in C# when declaring arrays.
Besides using a Dictionary as others have suggested, you could try using an enumeration instead, with values corresponding to your specific array indices and descriptions (using the Description attribute) corresponding to the string values.
private enum Pets
{
[Description("GreyHound")]
Greyhound = 5,
[Description("Bulldog")]
Bulldog = 29
}
For the record, I agree with everyone that a Dictionary is probably more appropriate. But you can write a little method to pull off what you want:
public static T[] CreateArray<T>(params Tuple<int, T>[] values)
{
var sortedValues = values.OrderBy(t => t.Item1);
T[] array = new T[sortedValues.Last().Item1 + 1];
foreach(var value in sortedValues)
{
array[value.Item1] = value.Item2;
}
return array;
}
And call it like this:
string[] myArray = CreateArray(new Tuple<int, string>(34, "cat"), new Tuple<int, string>(12, "dog"));
If C# receives the syntactic sugar for Tuple that many people seem to want, this would get a tad cleaner looking.
Is this a good idea? Almost certainly not, but I'll leave that for the OP to judge.
You can not do that in the initializer, you need to first specify the size of the array and then add items at specific locations.
private static readonly string[] Pets = new string[42];
and then in a static constructor you insert your items.
private static MyClass
{
Pets[29] = "Bulldog";
Pets[5] = "Greyhound";
}
But as other have suggested: use the Dictionary<int, string>.
You don't need a string array, but instead a Dictionary.
Take a look at link text, there's a fine example there (which I adapted here):
Dictionary<int, string> d = new Dictionary<int, string>();
d.Add(2, "cat");
d.Add(1, "dog");
d.Add(0, "llama");
d.Add(-1, "iguana");