Process a list while appending it in C#? - c#

Is there some kind of list like collection I can use in .NET to allow me to append to it while iterating?
var ls = new List<int>();
ls.Add(5);
foreach (var v in ls) {
if (v > 0)
ls.Add(v - 1);
}
//Alternative
var e = ls.GetEnumerator();
while (e.MoveNext()) {
if (e.Current > 0)
ls.Add(e.Current - 1);
}

To mimic such foreach loop, I suggest using for loop, while iterating backward:
for (int i = ls.Count - 1; i >= 0; --i) {
var v = ls[i];
//TODO: put relevant code from existing foreach loop here
}
Or if you have to loop forward
int n = ls.Count; // we don't want iterate the items appended
for (int i = 0; i < n; ++i) {
var v = ls[i];
//TODO: put relevant code from existing foreach loop here
}
In case you do want itetate appended items (see comments below) standard for loop is enough:
for (int i = 0; i < ls.count; ++i) {
var v = ls[i];
//TODO: put relevant code from existing foreach loop here
}
Finally, you can iterate a copy of the original list:
foreach (var v in ls.ToList()) { // ls.ToList() is a shallow copy of the ls
...
}

Using for would allow this. foreach does not allow for the modification of a enumerable while iterating it.
var ls = new List<int>();
ls.Add(5);
for (int i = 0; i < ls.Count; i++) {
var v = ls[i];
if (v > 0)
ls.Add(v - 1);
}
foreach (var v in ls) {
Console.WriteLine(v.ToString());
}
Output:
5
4
3
2
1
0

I don't think that you can directly append to any iterable object while iterating.
But what you can do is create a temporary list like that:
var ls = new List<int>();
ls.Add(5);
var tempList = new List<int>();
foreach(var v in ls){
if(v>0)
tempList.Add(v-1);
}
//Update list
foreach(var v in tempList){
ls.Add(v);
}
//Dont forget to clear the tempList if you need it again !

To include the new additions in the iterations use the index:
for (int i = 0; i < ls.Count; i++)
{
if (ls[i] > 0) ls.Add(ls[i] - 1);
}
To exclude them (and also keep the foreach) use a temporary copy of the List:
foreach (int i in ls.ToList())
{
if (i > 0) ls.Add(i - 1);
}

IMO; This seems to need a recursive solution instead; something like this:
public List<int> AddByReduceNo(List<int> list, int no)
{
if (no > 0)
{
list.Add(no - 1);
return AddByReduceNo(list, no - 1);
}
return list;
}
That after ls.Add(5) use ls = AddByReduceNo(ls, 5);,
or just use ls = AddByReduceNo(ls, 6);

You can have a look at the BlockingCollection class, and see if it fits your needs.
This class has a method GetConsumingEnumerable which gives you an IEnumerable that allows you to iterate over the items that were in the collection at that specific point in time. In the meanwhile, another thread can continue adding items to the collection.
This is especially usefull if you have a consumer and a producer thread.

Related

Why not all the items in the List that not contains the string not removed from the List?

var g = urls;
if (g.Count > 1)
{
for(int i = g.Count - 1; i > 0; i--)
{
if (!g[i].Contains("Test"))
{
g.RemoveAt(i);
}
}
}
I create a copy of the List then checking for specific string in each item but there are 23 items left in g one of them is not containing the word "Test" but was not removed it's the first item in the list at index 0.
Because your for loop is not touching element present at index 0, to fix this issue update your for loop to
for(int i = g.Count - 1; i >= 0; i--)
{ //^^^^ This is missing in your code
if (!g[i].Contains("Test"))
{
g.RemoveAt(i);
}
}
To make it more readable, you can traverse from start instead of reverse traversal and store expected element of g into a new list.
var result = new List<string>();
for(int i = 0; i < g.Count; i++)
{
if (g[i].Contains("Test"))
{
result.Add(g[i]);
}
}
To make it more elegant you can use Linq Where() clause,
var result = g.Where(x => x.Contains("Test")).ToList();
If you are looking for a solution which actually update input list (in Your case it is g), then you can use solution suggested by #canton7,
g.RemoveAll(item => !item.Contains("Test"))
Console.WriteLine(string.Join(" ", g));
.RemoveAll()
.NET Fiddle
var g = urls.Where(u => u.Contains("Test")).ToList();

How to pass dictionary values without having to iterate using a loop in c#

I am using Dictionary class as follows
Dictionary<string, string> dict = new Dictionary<string, string>()
{
{"1", "One"}
{"2", "Two"}
{"3", "three"}
{"4", "four"}
};
Now I am trying to get the value of each of the keys and pass them as parameter to a function. Something like :
myFunction(<get the first key and pass its value as parameter>);
myFunction(<get the second key and pass its value as parameter>);
myFunction(<get the third key and pass its value as parameter>);
myFunction(<get the fourth key and pass its value as parameter>);
So these are four calls to the function.
I cannot use a for loop here obviously because if I do so, say for example I start the loop from 1, then the value for the first run of the loop will be 1 and it will pick up the first key throughout these four calls of the function which I do not want. I want to get 1 in the first call of the functions, get second value in the second call and so on.
I am not able to figure out a way to do this. Any suggestions would be of great help.
The same key for four calls?
Or how not to do loops.
I cannot use a for loop here obviously because if I do so, say for example I start the loop from 1, then the value for the first run of the loop will be 1 and it will pick up the first key throughout these four calls of the function which I do not want. I want to get 1 in the first call of the functions, get second value in the second call and so on.
Don't put the four calls in the loop.
If you do either this:
var keys = new List<string>(dict.Keys);
for (var index = 0; index < keys.Count; index++)
{
myFunction(dict[keys[index]]);
myFunction(dict[keys[index]]);
myFunction(dict[keys[index]]);
myFunction(dict[keys[index]]);
}
Or this:
var values = new List<string>(dict.Values);
for (var index = 0; index < values.Count; index++)
{
myFunction(values[index]);
myFunction(values[index]);
myFunction(values[index]);
myFunction(values[index]);
}
Or this:
foreach (var key in dict.Keys)
{
myFunction(dict[key]);
myFunction(dict[key]);
myFunction(dict[key]);
myFunction(dict[key]);
}
Or this:
foreach (var pair in dict)
{
myFunction(pair.Value);
myFunction(pair.Value);
myFunction(pair.Value);
myFunction(pair.Value);
}
Or this:
foreach (var value in dict.Values)
{
myFunction(value);
myFunction(value);
myFunction(value);
myFunction(value);
}
You will get hte function myFunction being called with the same value four times, for each value.
How to do for or foreach loops
Instead, put a single call in the loop. Remember that the loop is used to repeat something, so by placing it in the loop it will be repeated.
So do this:
var keys = new List<string>(dict.Keys);
for (var index = 0; index < keys.Count; index++)
{
myFunction(dict[keys[index]]);
}
So do this:
var values = new List<string>(dict.Values);
for (var index = 0; index < values.Count; index++)
{
myFunction(values[index]);
}
Or this:
foreach (var key in dict.Keys)
{
myFunction(dict[key]);
}
Or this:
foreach (var pair in dict)
{
myFunction(pair.Value);
}
Or this:
foreach (var value in dict.Values)
{
myFunction(value);
}
You may also do this:
var keys = new List<string>(dict.Keys);
keys.ForEach(key => myFunction(dict[key]));
Or this:
var values = new List<string>(dict.Values);
values.ForEach(value => myFunction(value));
Or if you prefer to throw some Linq in the mix (which I presume, since you added the Linq tag), you can do this:
dict.Keys.ToList().ForEach(key => myFunction(dict[key]));
This also works:
dict.Values.ToList().ForEach(value => myFunction(value));
How to do while loops
Let's say that you don't want to do a for or foreach loop at all. Well, lets see...
A for loop like this one:
var keys = new List<string>(dict.Keys);
for (var index = 0; index < keys.Count; index++)
{
myFunction(dict[keys[index]]);
}
Can be done like this:
var keys = new List<string>(dict.Keys);
var index = 0;
while (index < keys.Count)
{
myFunction(dict[keys[index]]);
index++
}
And a foreach loop like this one:
foreach (var key in dict.Keys)
{
myFunction(dict[key]);
}
Can be done like this:
var enumerator = dict.Keys.GetEnumerator();
try
{
while (enumerator.MoveNext())
{
var key = enumerator.Current;
myFunction(dict[key]);
}
}
finally
{
enumerator.Dispose();
}
Of course, you can also do it like this:
var enumerator = dict.Values.GetEnumerator();
try
{
while (enumerator.MoveNext())
{
var value = enumerator.Current;
myFunction(value);
}
}
finally
{
enumerator.Dispose();
}
Or like this:
var enumerator = dict.GetEnumerator();
try
{
while (enumerator.MoveNext())
{
var pair = enumerator.Current;
myFunction(pair.Value);
}
}
finally
{
enumerator.Dispose();
}
This transformation is similar to the one the compiler does internally. By doing this, you may have more flexibility in some situations... yet, it is also more error prone.
How to not do loop
Let's pretend that you don't want to loop at all. This is possible if you know at compile time what is the number of elements. We can get there by unrolling a for, such as the while we had before:
var keys = new List<string>(dict.Keys);
var index = 0;
while (index < keys.Count)
{
myFunction(dict[keys[index]]);
index++
}
Turn the while into an if and repeat it. The result looks like this:
var keys = new List<string>(dict.Keys);
var index = 0;
if (index < keys.Count)
{
myFunction(dict[keys[index]]);
index++
}
if (index < keys.Count)
{
myFunction(dict[keys[index]]);
index++
}
if (index < keys.Count)
{
myFunction(dict[keys[index]]);
index++
}
if (index < keys.Count)
{
myFunction(dict[keys[index]]);
index++
}
Well, if know the value of index and the number of items in the dictionary, we know when index < keys.Count is true. So we can remove those if statements and repelace them with their inner code (since they are true). We end up with this:
var keys = new List<string>(dict.Keys);
var index = 0;
myFunction(dict[keys[index]]);
index = 1;
myFunction(dict[keys[index]]);
index = 2;
myFunction(dict[keys[index]]);
index = 3;
myFunction(dict[keys[index]]);
index = 4;
Finally, we inline the index variable:
var keys = new List<string>(dict.Keys);
myFunction(dict[keys[0]]);
myFunction(dict[keys[1]]);
myFunction(dict[keys[2]]);
myFunction(dict[keys[3]]);
Ta-Da! no loop.
Of course, you can also do it like this:
var values = new List<string>(dict.Values);
myFunction(values[0]);
myFunction(values[1]);
myFunction(values[2]);
myFunction(values[3]);
What you really have to know that a dictionary is not ordered. Saying that you want the "first" key just does not make sense. Sure you can convert the KeyCollection you got from the Keys property of the dictionary into a List<string> but that can result in any arbitrary different order.
If by the "first" key you mean the key "1", and by the "second" key you mean the key "2" and so on, then I think a List<string> is a better fit for this. It is ordered and you can use numbers to access the elements.
Also, I don't get it why for loops won't work. Try this:
for (int i = 1 ; i <= 4 ; i++) {
myFunction(dict[i.toString()]);
}
This will pass values in the order of "One" -> "Two" -> "three" -> "four".
You can get the keys using this code,
List<string> keyList = new List<string>(dict.Keys);
and then pass to the function with the index,
myFunction(keyList[0]);
Why can't you use loops? A foreach would do you just fine:
foreach (string key in dict.Keys)
{
myFunction(dict[key]);
}
foreach(var item in dict)
{
myFunction(item.Value);
}
OR
foreach(var dictValue in dict.Values)
{
myFunction(dictValue);
}
Not sure why you think loop wont work here

How to performantly get every (unordered) pair of different collection elements if random access is not available

Example: I have the collection {1, 2, 3, 4}.
I want to get all (unordered) pairs of different elements, which are:
{1,2}, {1,3}, {1,4}, {2,3}, {2,4}, {3,4}.
If I have an IList, I can do it like this:
IList<MyType> list = ... // fill the list elements
for (int i = 0; i < list.Count - 1; i++)
for (int j = i+1; j < list.Count; j++)
{
... // now we have the pair of list[i] and list[j]
}
For a LinkedList I also know how to do it; it is almost the same except that instead of indexes i and j, we have two LinkedListNodes fst and snd. Whenever we call fst.Next, we will then set snd = fst.Next.
For a list of n elements, the above approach takes (n-1)*n/2 iteration steps. (For i = 0 we have j = 1 ... n-1, so n-1 steps. For i = 1 we have j = 2 ... n-1, so n-2 steps. And so on. This sums up to (n-1) + (n-2) + ... + 3 + 2 + 1 = (n-1)*n/2 steps.)
Is there a way to do it with any ICollection? I thought an IEnumerator could do the trick, but it seems there is no way to tell an IEnumerator "Move to that reference!" like I can do with LinkedListNodes.
EDIT:
I am NOT looking for this solution:
foreach (MyType a in list)
foreach (MyType b in list)
{
if (a == b)
continue;
... // now we have the pair of a and b
}
For a collection of n elements, this approach takes n^2 iteration steps which is a bit more than double than the above approach, so it is clearly not as performant.
EDIT:
Turning the collection into a List beforehand seems to be the easiest way, and the performance penalty is negligible for large n, because it only adds n steps to the whole interation (the new list must be filled by the n elements). So I'll just stick with it.
IEnumerable is a forward-only iterator; ICollection does not have indexed access. What you could do is get the enumerable into a buffer during the first iteration, and afterwards use the nested for loops.
var enumerable = Enumerable.Range(0, 10);
var buffer = new List<int>();
using (var enumerator = enumerable.GetEnumerator())
{
if (enumerator.MoveNext())
{
buffer.Add(enumerator.Current);
while (enumerator.MoveNext())
{
var current = enumerator.Current;
buffer.Add(current);
Handle(buffer[0], current);
}
}
}
for (int i = 1; i < buffer.Count - 1; i++)
for (int j = i + 1; j < buffer.Count; j++)
Handle(buffer[i], buffer[j]);
Alternatively, if you don't care about going through the items one more time, you could just use enumerable.ToArray() and then use the nested for on that array.
Edit: Based on the discussion in comments and the edited question it seems that copying the enumerable in a list is the best course of action.
Old answer:
It seems to me that you need to put the items into some kind of hashtable data structure.
Here is a LINQ based solution that uses GroupBy
var items = new List<int> { 1, 2, 3, 2, 3 };
var groupedItems = from i in items
group i by i into g
select g;
foreach (var group in groupedItems)
{
//group.Key stores the key of the grouping
foreach (var item in group) //group contains items with the same key
{
//Do something
Console.WriteLine(item);
}
}
Here each group contains items with the same key (in this example because the item is an int the item is the key but you can group by whatever expression you want)
Alternatively you can group stuff on your own using a dictionary
var items = new List<int> { 1, 2, 3, 2, 3 };
var itemsDictionary = new Dictionary<int, List<string>>();
foreach (int i in items)
{
List<string> repeatedValues;
if(itemsDictionary.TryGetValue(i, out repeatedValues))
{
repeatedValues.Add(i.ToString());
}
else
{
itemsDictionary.Add(i, new List<string> { i.ToString() });
}
}
foreach (KeyValuePair<int, List<string>> kvp in itemsDictionary)
{
//do whatever is needed kvp.Value
}
In this example I've used a string to emulate a key of int and a value of different type. I think both these solutions are NlogN
Alternatively - sort the collection in a list - all equal elements will be placed one after another. This will be NlogN solution.

Proper way to iterate this?

I have a list of strings that are semicolon separated.
There will always be an even number because the first is the key, the next is the value,
ex:
name;Milo;site;stackoverflow;
So I split them:
var strList = settings.Split(';').ToList();
But now I would like to use a foreach loop to put these into a List<ListItem>
I am wondering if it can be done via iteration, or if I have to use a value 'i' to get [i] and [i+1]
It can be done with LINQ but I am not sure this one is better
var dict = input.Split(';')
.Select((s, i) => new { s, i })
.GroupBy(x => x.i / 2)
.ToDictionary(x => x.First().s, x => x.Last().s);
You can also use moreLinq's Batch for this
var dict2 = input.Split(';')
.Batch(2)
.ToDictionary(x=>x.First(),x=>x.Last());
I can't compile this, but this should work for you:
var list = new List<ListItem>();
for (int i = 0; i < strList.Count; i++)
{
i++;
var li = new ListItem(strList[i - 1], strList[i]);
list.Add(li);
}
again, I'm not in a position to fully recreate your environment but since the first is the key and second is the value, and you're sure of the state of the string, it's a pretty easy algorithm.
However, leveraging a foreach loop would still require you to know a bit more about the index so it's a little more straight forward with a basic for loop.
First, a valuable helper function I use. It is similar to GroupBy except it groups by sequential indexes rather than some key.
public static IEnumerable<List<T>> GroupSequential<T>(this IEnumerable<T> source, int groupSize, bool includePartialGroups = true)
{
if (groupSize < 1)
throw new ArgumentOutOfRangeException("groupSize", groupSize, "Must have groupSize >= 1.");
var group = new List<T>(groupSize);
foreach (var item in source)
{
group.Add(item);
if (group.Count == groupSize)
{
yield return group;
group = new List<T>(groupSize);
}
}
if (group.Any() && (includePartialGroups || group.Count == groupSize))
yield return group;
}
Now you can simply do
var listItems = settings.Split(';')
.GroupSequential(2, false)
.Select(group => new ListItem { Key = group[0], Value = group[1] })
.ToList();
if you want to use foreach
string key=string.Empty;
string value=string.Empty;
bool isStartsWithKey=true;
var strList = settings.Split(';').ToList()
foreach(var item in strList)
{
if(isStartsWithKey)
{
key=item;
}
else
{
value=item;
//TODO: now you can use key and value
}
isStartsWithKey=!isStartsWithKey;
}
List<int, string> yourlist;
for(int i=0;i<strList.length/2;i++)
{
yourlist.add(new ListItem(strList[i*2], strList[i*2+1]));
}
this seems to me to be the simpliest way
for(var i = 0; i < strList.Count(); i = i + 2){
var li = new listItem (strList[i], strList[i + 1];
listToAdd.Add(li);
}
Updated Example
for (var i = 0; i < strList.Count(); i = i + 2){
if (strList.ContainsKey(i) && strList.ContainsKey(i + 1)){
listToAdd.Add(new listItem(strList[i], strList[i + 1]);
}
}

Is there another way to take N at a time than a for loop?

Is there a more elegant way to implement going 5 items at a time than a for loop like this?
var q = Campaign_stats.OrderByDescending(c=>c.Leads).Select(c=>c.PID).Take(23);
var count = q.Count();
for (int i = 0; i < (count/5)+1; i++)
{
q.Skip(i*5).Take(5).Dump();
}
for(int i = 0; i <= count; i+=5)
{
}
So you want to efficiently call Dump() on every 5 items in q.
The solution you have now will re-iterate the IEnumerable<T> every time through the for loop. It may be more efficient to do something like this: (I don't know what your type is so I'm using T)
const int N = 5;
T[] ar = new T[N]; // Temporary array of N items.
int i=0;
foreach(var item in q) { // Just one iterator.
ar[i++] = item; // Store a reference to this item.
if (i == N) { // When we have N items,
ar.Dump(); // dump them,
i = 0; // and reset the array index.
}
}
// Dump the remaining items
if (i > 0) {
ar.Take(i).Dump();
}
This only uses one iterator. Considering your variable is named q, I'm assuming that is short for "query", which implies this is against a database. So using just one iterator may be very beneficial.
I may keep this code, and wrap it up in an extension method. How about "clump"?
public static IEnumerable<IEnumerable<T>> Clump<T>(this IEnumerable<T> items, int clumpSize) {
T[] ar = new T[clumpSize];
int i=0;
foreach(var item in items) {
ar[i++] = item;
if (i == clumpSize) {
yield return ar;
i = 0;
}
}
if (i > 0)
yield return ar.Take(i);
}
Calling it in the context of your code:
foreach (var clump in q.Clump(5)) {
clump.Dump();
}
try iterating by 5 instead!
for(int i = 0; i < count; i += 5)
{
//etc
}
Adding more LINQ with GroupBy and Zip:
q
// add indexes
.Zip(Enumerable.Range(0, Int32.MaxValue),(a,index)=> new {Index=index, Value=a})
.GroupBy(m=>m.Index /5) // divide in groups by 5 items each
.Select(k => {
k.Select(v => v.Value).Dump(); // Perform operation on 5 elements
return k.Key; // return something to satisfy Select.
});

Categories

Resources