Use List<T>ForEach to add element to HashTable - c#

I have a list of string values that I want add to a hashtable or other array that can be accessed by key/index but cannot implement it. I have this working how I want but its ugly
List<string> valueList = new List<string>();
valueList.Add("1");
valueList.Add("2");
valueList.Add("3");
Hashtable p = new Hashtable();
valueList.ForEach(delegate(string f) { p.Add(valueList.FindIndex(v => v == f), f); });
EDIT: After James reminded me that a List will return values by index I went with a List and this is what I have ended up with
valueList.ForEach(f => sequenceList.Add(int.Parse(f)));

Even if it compiled, it wouldn't work - calling GetEnumerator().Current will always fail because it'll give you a new iterator positioned before the first item.
What do you want the key for each item to be? If it's just its position within the list, I don't see the benefit that gives you over a list (which is already indexed by int). However, you can do it like this (assuming that valueList is a List<string>:
var dictionary = valueList.Select((item, index) => new { item, index })
.ToDictionary(x => x.index, x => x.item);
Adding it to an existing dictionary, I'd just do:
for (int i=0; i < valueList.Count; i++)
{
dictionary[i] = valueList[i];
}
Not everything has to be done with lambdas :)
Note that this won't have quite the same effect as using FindIndex if you have repeated values.

Try this:
valueList.ForEach(x => htable.Add(valueList.FindIndex(y => y == x), x));
Although, there's really no reason not to use a for here
for (var index = 0; index < valueList.Count; index++)
{
htable.Add(index, valueList[index]);
}
It's more lines of code, but it's more straightforward and will perform much better (findIndex is far less efficient than using the index from the for statement).

Assuming you want the strings to be the keys and the index to be the value:
Hashtable ht = new Hashtable();
for (var i = 0; i <= valueList.Count; i++)
{
ht.Add(valueList[i], i);
}
Otherwise switch the ht.Add parameters around. However, if that is the case you would be best just to leave it as a List < string >.

List<string> list = new List<string>{"w", "y", "u", "i", "n"};
HashSet<string> hset = new HashSet<string>(list);

Using ForEach for this is not efficient, as you have to use FindIndex to find out where you are. It works, but you will do a lot of extra work:
valueList.ForEach(x => htable.Add(valueList.FindIndex(y => y == x), x));
It's better to just use a regular loop, so that you get the index without having to seek through the table:
for (int i = 0; i < valueList.Count; i++) {
htable.Add(i, valueList[i]);
}

Related

How can I add have a property of a list populated with a unique number when I populate the list?

I have this code:
List<Phrase> cardSetPhrases = App.DB.GetPhrasesForCardSet(cardSetId);
The Phrase object has an int Index property.
Is there some way using LINQ that I could populate this with a sequence number for each row returned from the right hand side?
I did think about something like this:
foreach (var x in App.cardSetWithWordCount.Select((r, i) => new { Row = r, Index = i }))
But I wondering if there is a more concise way I could do it.
Why don't you use the hash code for each element?
cardSetPhrases.ForEach(x => x.Index = x.GetHashCode());
For a sequence, I think you need to rely on a separate variable
int i = 0;
cardSetPhrases.ForEach(x => x.Index = i++);

How can I find the first items in a list with a different value for a property using Linq?

I have an ordered list of objects, and I would like to find the index of each item where a property changes, and get a dictionary/list of pairs matching index to property. For example, finding the index of each new first letter in a list of words ordered alphabetically.
I can do this with a foreach loop:
Initials = new Dictionary<char, int>();
int i = 0;
foreach (var word in alphabeticallyOrderedList))
{
if (!Initials.ContainsKey(word.First()))
{
Initials[word.First()] = i;
}
i++;
}
But I feel like there should be an elegant way of doing this with Linq.
You could have the same functionality with LINQ by using the overload of Select that exposes the index and by using GroupBy + ToDictionary:
Initials = alphabeticallyOrderedList
.Select((word, index) => new { Word = word, WordIndex = index })
.GroupBy(x => x.Word[0])
.ToDictionary(charGroup => charGroup.Key, charGroup => charGroup.First().WordIndex);
But to quote myself:
LINQ is not always more readable, especially when indexes are important. You also lose some debugging, exception handling and logging capabilities if you use a large LINQ query

c# - How to iterate through a dictionary and compare values?

I'm teaching myself c# and working on my own mini project. The program populates an array with random numbers, the program returns the number (0-15) and the number of occurrences it appears in the array. I stored these values in a dictionary as I wanted to sort the values without losing the key mapped to it.
The sorted values are then stored into another dictionary and now I want to be able to iterate through the dictionary and get the key with the highest value. In other words print to the console the number with the most occurrences. As the dictionary is sorted, the last number will be the highest value.
However there could be more than one number tied for the most occurrences and that's where I'm stuck on. If the numbers 4,5,6,7 all appear the most number of times, i want to be able to print that to the console.
Dictionary<int, int> dic = new Dictionary<int, int>();
//iterates through numbers 0-15
for (int y = 0; y <= 15; y++)
{
int m = 0;
//iterates through entire array
for (int i = 0; i < Arr.Length; i++)
{
//comparisons
if (y == Arr[i])
{
m++;
}
}
//Inserts number and count into the dictionary
dic.Add(y,m);
}
//Sorts the dictionary and adds the sorted one into a new dictionary
Dictionary<int, int> dic2 = new Dictionary<int, int>();
foreach (KeyValuePair<int, int> value in dic.OrderBy(key => key.Value))
{
Console.WriteLine("{0} appears {1} times ", value.Key, value.Value);
dic2.Add(value.Key, value.Value);
}
//Finds the keys with most common occurance
KeyValuePair<int, int> e = dic2.Last();
foreach (KeyValuePair<int, int> comp in dic2)
{
if (dic.Last() == dic[comp])
{
//something goes here
Console.WriteLine("Most common number is {0}", e.Key);
}
}
I'm not sure whether to use indexes to compare using the key or if there is another way to do this like I have tried above, using a foreach loop
I wouldn't use the current approach at all, to be honest - you're doing much more work than you need to. LINQ gives you much better tools than this. You can use GroupBy to make it all cleaner:
var pairs = array.GroupBy(x => x)
.Select(g => new { Key = g.Key, Count = g.Count() }
.OrderByDescending(pair => pair.Count)
.ToList();
That gets you all the key/count pairs, most-frequent first. The display part should then be reasonably simple, e.g.
// Note: this relies on the initial array being non-empty
var highestCount = pairs.First().Count;
foreach (var pair in pairs.TakeWhile(pair => pair.Count == highestCount))
{
Console.WriteLine("{0}: {1}", pair.Key, pair.Count);
}
Just to be clear, the code above replaces all the code in your question. You don't need a Dictionary<,> at all.
You could use a linq query to find the number of ocurrencies for each key and count it. After, return a anon object with the Key and total, for sample:
var q = from k in dic
let t = dic.Count(x => x.Value == k.Key)
select new { Key = k.Key, Total = t };
var max = q.OrderByDescending(x => Total).First();
Console.WriteLine("Most common number is {0} with {1} ocurrencies", max.Key, max.Total);

Linq equivalent of for in foreach

I'm borrowing code from this question as I went there for inspiration. I have a list of objects, the object has an integer property and I want to foreach the list and the loop the number of integers.
It's a very basic for inside a foreach but I suspect I could use a SelectMany but can't get it working. The following code works but I would like a linq version.
//set up some data for our example
var tuple1 = new { Name = "Tuple1", Count = 2 };
var tuple2 = new { Name = "Tuple2", Count = 3 };
//put the tuples into a collection
var tuples = new [] { tuple1, tuple2 };
foreach(var item in tuples)
{
for(int i = 0; i < item.Count; i++)
Console.WriteLine(item.Name);
}
var flattened = tuples.SelectMany(t => Enumerable.Repeat(t.Name, t.Count));
foreach(var word in flattened)
{
Console.WriteLine(word);
}
You can use SelectMany; you simply need to generate sequences:
tuples.SelectMany(t => Enumerable.Repeat(t.Name, t.Count))
There is no Values property in your anonymous type. But i assume that you mean the Count property instead and you want to repeat the name this number. You can either use Enumerable.Range or Enumerable.Repeat:
IEnumerable<String> tupleNames = tuples
.Select(t => string.Join(Environment.NewLine, Enumerable.Repeat(t.Name, t.Count)));
Console.Write(string.Join(Environment.NewLine, tupleNames));
Output:
Tuple1
Tuple1
Tuple2
Tuple2
Tuple2
There is no linq equivalent of a foreach. You should use an actual foreach to iterate an IEnumerable and perform an action on each item.

Use ToDictionary to create a dictionary

I have two string lists which have same size.
I want to create a dictionary, the key is from listA, the value is from listB.
What is the fast way?
I used the code:
List<string> ListA;
List<string> ListB;
Dictionary<string,string> dict = new Dictionary<string,string>();
for(int i=0;i<ListA.Count;i++)
{
dict[key] = listA[i];
dict[value]= listB[i];
}
I don't like this way, can I use ToDictionary method?
Starting with .NET 4.0, you can do it using LINQ's Zip method, like this:
var res = ListA.Zip(ListB, (a,b) => new {a, b})
.ToDictionary(p=>p.a, p=>p.b);
[Zip] method merges each element of the first sequence with an element that has the same index in the second sequence.
You could create an anonymous type with the index which you can use to get the B at this index.
Dictionary<string, string> dict = ListA
.Select((a, i) => new { A = a, Index = i })
.ToDictionary(x => x.A, x => ListB.ElementAtOrDefault(x.Index));
Note that the value would be null in case ListB is smaller than ListA.
I would not bother (if it is possible) as your version is readable, easy to debug and quicker than any other LINQ solutions (especially if you are working with big list).
I wouldn't change your version.
The following piece of code is more readable than LINQ stuff in your case, IMHO.
var ListA = new List<string>();
var ListB = new List<string>();
var dict = new Dictionary<string, string>();
for (int i = 0; i < ListA.Count; i++)
{
dict.Add(ListA[i], ListB[i]);
}

Categories

Resources