How to replace an element in a Collection - c#

The thing I wanna do would appear really simple - I want to find an element in an ICollection<T> that satisfies a given predicate and replace it with another. In C++ I would write this like:
for(auto &element : collection) {
if(predicate(elem)) {
element = newElement;
}
}
Grab the element by reference and reassign it. However doing
foreach(ref var element in collection)
in C# fails to compile, and I'm unsure if it'd even do what I want if it did compile. How do I access the physical reference within a collection to modify it?
My method signature if it helps:
public static void ReplaceReference<T>(
ICollection<T> collection,
T newReference,
Func<T, bool> predicate)
EDIT:
Since it appears unclear, I cannot just take the ICollection<T> and change it to something else. I'm getting an ICollection - that's all I know and I can't change that. No matter how much I'd love this to be an IList, or IEasilyReplacable I can't influence that.

ICollection<T> wouldn't be the best for this scenario. IList<T> allows you to assign with the indexer.
Another option would be to create a new collection as you iterate.
You could also write some sort of wrapper that is the actual reference in the collection and holds the value:
ICollection<Wrapper<T>> collection = ...;
foreach(var wrapper in collection)
{
wrapper.Value = newValue;
}

As per my understanding you want to replace specific item in collection based on given predicate, I tried below code and it is works fine for me.
I've created a list of string with 4 items and i asked my generic method to search for string with value "Name 1" if it is true it should change it to value "Name 5".
I've tested it using console application so you can test it by creating forloop that show values of list using Console.WriteLine();
public void Main(string[] args)
{
List<string> list = new List<string>();
list.Add("Name 1");
list.Add("Name 2");
list.Add("Name 3");
list.Add("Name 4");
Func<string, bool> logicFunc = (listItemValue) => listItemValue == "Name 1";
ReplaceReference(list, "Name 5", logicFunc);
}
public static void ReplaceReference<T>(ICollection<T> collection, T newReference, Func<T, bool> predicate)
{
var typeName = typeof(T).Name;
var newCollection = collection.ToList();
for (int i = 0; i < newCollection.Count; i++)
{
if (predicate(newCollection[i]))
{
newCollection[i] = newReference;
}
}
}

So I bashed my head against the wall and came up with a really simple solution for the particular replace problem, which is to find, remove and then add.
var existing = collection.FirstOrDefault(predicate);
if (existing != null)
{
collection.Remove(existing);
collection.Add(newReference);
}
However, I see it as rather a workaround to my foreach issue, and have thus posted this question as a follow-up: Grab element from a Collection by reference in a foreach
EDIT:
For Daniel A. White's comment:
Handling only the first one was what I intended to do, but it can be easily changed to replace-all:
var existing = collection.Where(predicate);
foreach(var element in existing)
{
collection.Remove(element);
}
for(int i = 0; i < existing.Count); ++i)
{
collection.Add(newReference);
}
As for ordering - ICollection is not necessarily ordered. So the way for fixing that would be creating a new method with a less general signature
static void ReplaceReference<T>(
IList<T> list,
T newReference,
Func<T, bool> predicate)
that would use the indexer to replace the values
for(int i = 0; i < list.Count; ++i)
{
if(predicate(list[i]))
{
list[i] = newReference;
// break here if replace-one variant.
}
}
And now in the main method we check if our collection is an IList, therefore ordered, and pass it to the ordered version:
if(collection is IList<T> list)
{
ReplaceReference(list, newReference, predicate);
return;
}
===========================================================================
Sidenote: of course there is also the dumbo approach:
var newCollection = new List<T>();
foreach(var element in collection)
{
newList.Add(predicate(element) ? newReference : element);
}
collection.Clear();
foreach(var newElement in newCollection)
{
collection.Add(newElement);
}
but it's highly inefficient.

Related

C#: How to traverse all elements from a nested list, with variable nesting and variable type?

I want to create a function
void StringFromNestedList<T>(T theList);
theList could be of types such as
List<List<List<List<double>>>>
List<List<int>>
List<List<List<SomeCustomType>>>
and so on.
Let's assume for each element, I want to activate a function all elements are assumed to have, such as ToString()
If I knew the amount of nesting, and size of each list, for example 2 levels of 4 elements each, I would do something like
for (var i = 0; i < 4; i++)
{
for (var j = 0; j < 4; j++)
{
theList[i][j].ToString(); // yes, it doesnt really do anything
}
}
But I don't know how many for loops are required.
Is it doable?
I'm not sure trying to make it generic will gain you anything.
So, first assume that it'll just take an object.
void StringFromPossibleList(object theList)
Now, assume we don't want to deal with lists but with anything enumerable. Assume further that we've already got this function working - then for each item inside our enumerable, we can just call ourselves recursively!
{
var enu = theList as IEnumerable;
if(enu!=null)
{
foreach(var item in enu)
{
StringFromPossibleList(item);
}
}
else
{
theList.ToString();
}
}
By using recursion, we get as many levels of looping as it turns out we need.
An alternative iterative solution could be something like this:
public static IEnumerable<object> FlattenNestedLists(object obj)
{
var stack = new Stack();
stack.Push(obj);
while (stack.Count > 0)
{
var current = stack.Pop();
if (current is IEnumerable list)
{
foreach (var item in list)
{
stack.Push(item);
}
}
else
{
yield return current;
}
}
}
The primary advantage would be that the objects are returned, and can be processed by something else. A downside is potential boxing, you could avoid this an additional check, but you will need to consider the behavior if lists contain dissimilar objects.

Array, List, IEnumerable, CustomList class cast to one and iterate threw them

I am trying to figure out a way that tells me if a certain type is an array/list/ienumerable/collection ... I dont care what kind of it is even CustomLists so something like
FooList<T> : IList<T>
FooList : IList
or stuff like that.
I kinda hoped that a simple type.IsArray would be enough but sadly this isnt the case.
I need a way to check if its one of the above types and then check what the underlying type is, and than cast it to a Indexed based collection, where I can loop through the entries.
For a simple array this is all I need:
if (obj.GetType().IsArray)
{
var elementType = obj.GetType().GetElementType();
if (elementType.IsPrimitive == false)
{
var array = (Array)obj;
}
}
This should work for every collection, there could possible be.
Edit:
As recommended below, I should as/is to IEnumerable but with IEnumerable I have the problem that the I cannot set certain object inside this IEnumerable.
With array I have used the method array.SetValue(obj, index) which works fine.
When I loop threw the IEnumerable and try to set one entry like this:
var list = obj as IEnumarble;
if (list != null)
{
foreach (var item in list)
{
item = new object();
}
}
I am getting the following message:
Readonly local variable cannot be used as an assignment target.
You can try to cast it with the as operator:
var enumerable = list as IEnumerable;
if (enumerable != null)
{
foreach (object item in enumerable)
{
// ...
}
}
However, if you need to modify it you have to recreate it. For example by using a list which you fill in the loop. Then reassign it to the original variable.
Or you could check if the type is a ILIst in the first place (like an array or list), then you can use it`s indexer:
var ilist = list as IList;
if (ilist != null)
{
for (int i = 0; i < ilist.Count; i++)
{
ilist[i] = "new value";
}
}
IIRC, you could do a simple inheritence check for the enumerable interface via
if (FooList is IEnumerable)
// We have a List
You can also use Linq and do a
if (FooList.ToList().Count > 1)
// We have a List
But this would be rather unconventional.

Removing element from list with predicate

I have a list from the .NET collections library and I want to remove a single element. Sadly, I cannot find it by comparing directly with another object.
I fear that using FindIndex and RemoveAt will cause multiple traversals of the list.
I don't know how to use Enumerators to remove elements, otherwise that could have worked.
RemoveAll does what I need, but will not stop after one element is found.
Ideas?
List<T> has a FindIndex method that accepts a predicate
int index = words.FindIndex(s => s.StartsWith("x"));
if (index >= 0)
{
words.RemoveAt(index);
}
Removes first word starting with "x". words is assumed to be a List<string> in this example.
If you want to remove only the first element that matches a predicate you can use the following (example):
List<int> list = new List<int>();
list.Remove(list.FirstOrDefault(x => x = 10));
where (x => x = 10) is obviously your predicate for matching the objects.
EDIT: Now the OP has changed to use a LinkedList<T>, it's easy to give an answer which only iterates as far as it has to:
public static void RemoveFirst<T>(LinkedList<T> list, Predicate<T> predicate)
{
var node = list.First;
while (node != null)
{
if (predicate(node.Value))
{
list.Remove(node);
return;
}
node = node.Next;
}
}
In case someone need same thing, but for IList<T>
(Inspired by Strillo answer, but more efficient)
public bool Remove(this IList<T> list, Predicate<T> predicate)
{
for(int i = 0; i < list.Count; i++)
{
if(predicate(list[i]))
{
list.RemoveAt(i);
return true;
}
}
return false;
}

How to iterate over two arrays at once?

I have two arrays built while parsing a text file. The first contains the column names, the second contains the values from the current row. I need to iterate over both lists at once to build a map. Right now I have the following:
var currentValues = currentRow.Split(separatorChar);
var valueEnumerator = currentValues.GetEnumerator();
foreach (String column in columnList)
{
valueEnumerator.MoveNext();
valueMap.Add(column, (String)valueEnumerator.Current);
}
This works just fine, but it doesn't quite satisfy my sense of elegance, and it gets really hairy if the number of arrays is larger than two (as I have to do occasionally). Does anyone have another, terser idiom?
You've got a non-obvious pseudo-bug in your initial code - IEnumerator<T> extends IDisposable so you should dispose it. This can be very important with iterator blocks! Not a problem for arrays, but would be with other IEnumerable<T> implementations.
I'd do it like this:
public static IEnumerable<TResult> PairUp<TFirst,TSecond,TResult>
(this IEnumerable<TFirst> source, IEnumerable<TSecond> secondSequence,
Func<TFirst,TSecond,TResult> projection)
{
using (IEnumerator<TSecond> secondIter = secondSequence.GetEnumerator())
{
foreach (TFirst first in source)
{
if (!secondIter.MoveNext())
{
throw new ArgumentException
("First sequence longer than second");
}
yield return projection(first, secondIter.Current);
}
if (secondIter.MoveNext())
{
throw new ArgumentException
("Second sequence longer than first");
}
}
}
Then you can reuse this whenever you have the need:
foreach (var pair in columnList.PairUp(currentRow.Split(separatorChar),
(column, value) => new { column, value })
{
// Do something
}
Alternatively you could create a generic Pair type, and get rid of the projection parameter in the PairUp method.
EDIT:
With the Pair type, the calling code would look like this:
foreach (var pair in columnList.PairUp(currentRow.Split(separatorChar))
{
// column = pair.First, value = pair.Second
}
That looks about as simple as you can get. Yes, you need to put the utility method somewhere, as reusable code. Hardly a problem in my view. Now for multiple arrays...
If the arrays are of different types, we have a problem. You can't express an arbitrary number of type parameters in a generic method/type declaration - you could write versions of PairUp for as many type parameters as you wanted, just like there are Action and Func delegates for up to 4 delegate parameters - but you can't make it arbitrary.
If the values will all be of the same type, however - and if you're happy to stick to arrays - it's easy. (Non-arrays is okay too, but you can't do the length checking ahead of time.) You could do this:
public static IEnumerable<T[]> Zip<T>(params T[][] sources)
{
// (Insert error checking code here for null or empty sources parameter)
int length = sources[0].Length;
if (!sources.All(array => array.Length == length))
{
throw new ArgumentException("Arrays must all be of the same length");
}
for (int i=0; i < length; i++)
{
// Could do this bit with LINQ if you wanted
T[] result = new T[sources.Length];
for (int j=0; j < result.Length; j++)
{
result[j] = sources[j][i];
}
yield return result;
}
}
Then the calling code would be:
foreach (var array in Zip(columns, row, whatevers))
{
// column = array[0]
// value = array[1]
// whatever = array[2]
}
This involves a certain amount of copying, of course - you're creating an array each time. You could change that by introducing another type like this:
public struct Snapshot<T>
{
readonly T[][] sources;
readonly int index;
public Snapshot(T[][] sources, int index)
{
this.sources = sources;
this.index = index;
}
public T this[int element]
{
return sources[element][index];
}
}
This would probably be regarded as overkill by most though ;)
I could keep coming up with all kinds of ideas, to be honest... but the basics are:
With a little bit of reusable work, you can make the calling code nicer
For arbitrary combinations of types you'll have to do each number of parameters (2, 3, 4...) separately due to the way generics works
If you're happy to use the same type for each part, you can do better
if there are the same number of column names as there are elements in each row, could you not use a for loop?
var currentValues = currentRow.Split(separatorChar);
for(var i=0;i<columnList.Length;i++){
// use i to index both (or all) arrays and build your map
}
In a functional language you would usually find a "zip" function which will hopefully be part of a C#4.0 . Bart de Smet provides a funny implementation of zip based on existing LINQ functions:
public static IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(
this IEnumerable<TFirst> first,
IEnumerable<TSecond> second,
Func<TFirst, TSecond, TResult> func)
{
return first.Select((x, i) => new { X = x, I = i })
.Join(second.Select((x, i) => new { X = x, I = i }),
o => o.I,
i => i.I,
(o, i) => func(o.X, i.X));
}
Then you can do:
int[] s1 = new [] { 1, 2, 3 };
int[] s2 = new[] { 4, 5, 6 };
var result = s1.Zip(s2, (i1, i2) => new {Value1 = i1, Value2 = i2});
If you're really using arrays, the best way is probably just to use the conventional for loop with indices. Not as nice, granted, but as far as I know .NET doesn't offer a better way of doing this.
You could also encapsulate your code into a method called zip – this is a common higher-order list function. However, C# lacking a suitable Tuple type, this is quite crufty. You'd end up returning an IEnumerable<KeyValuePair<T1, T2>> which isn't very nice.
By the way, are you really using IEnumerable instead of IEnumerable<T> or why do you cast the Current value?
Use IEnumerator for both would be nice
var currentValues = currentRow.Split(separatorChar);
using (IEnumerator<string> valueEnum = currentValues.GetEnumerator(), columnEnum = columnList.GetEnumerator()) {
while (valueEnum.MoveNext() && columnEnum.MoveNext())
valueMap.Add(columnEnum.Current, valueEnum.Current);
}
Or create an extension methods
public static IEnumerable<TResult> Zip<T1, T2, TResult>(this IEnumerable<T1> source, IEnumerable<T2> other, Func<T1, T2, TResult> selector) {
using (IEnumerator<T1> sourceEnum = source.GetEnumerator()) {
using (IEnumerator<T2> otherEnum = other.GetEnumerator()) {
while (sourceEnum.MoveNext() && columnEnum.MoveNext())
yield return selector(sourceEnum.Current, otherEnum.Current);
}
}
}
Usage
var currentValues = currentRow.Split(separatorChar);
foreach (var valueColumnPair in currentValues.Zip(columnList, (a, b) => new { Value = a, Column = b }) {
valueMap.Add(valueColumnPair.Column, valueColumnPair.Value);
}
Instead of creating two seperate arrays you could make a two-dimensional array, or a dictionary (which would be better). But really, if it works I wouldn't try to change it.

How do you get the index of the current iteration of a foreach loop?

Is there some rare language construct I haven't encountered (like the few I've learned recently, some on Stack Overflow) in C# to get a value representing the current iteration of a foreach loop?
For instance, I currently do something like this depending on the circumstances:
int i = 0;
foreach (Object o in collection)
{
// ...
i++;
}
Ian Mercer posted a similar solution as this on Phil Haack's blog:
foreach (var item in Model.Select((value, i) => new { i, value }))
{
var value = item.value;
var index = item.i;
}
This gets you the item (item.value) and its index (item.i) by using this overload of LINQ's Select:
the second parameter of the function [inside Select] represents the index of the source element.
The new { i, value } is creating a new anonymous object.
Heap allocations can be avoided by using ValueTuple if you're using C# 7.0 or later:
foreach (var item in Model.Select((value, i) => ( value, i )))
{
var value = item.value;
var index = item.i;
}
You can also eliminate the item. by using automatic destructuring:
foreach (var (value, i) in Model.Select((value, i) => ( value, i )))
{
// Access `value` and `i` directly here.
}
The foreach is for iterating over collections that implement IEnumerable. It does this by calling GetEnumerator on the collection, which will return an Enumerator.
This Enumerator has a method and a property:
MoveNext()
Current
Current returns the object that Enumerator is currently on, MoveNext updates Current to the next object.
The concept of an index is foreign to the concept of enumeration, and cannot be done.
Because of that, most collections are able to be traversed using an indexer and the for loop construct.
I greatly prefer using a for loop in this situation compared to tracking the index with a local variable.
Finally C#7 has a decent syntax for getting an index inside of a foreach loop (i. e. tuples):
foreach (var (item, index) in collection.WithIndex())
{
Debug.WriteLine($"{index}: {item}");
}
A little extension method would be needed:
using System.Collections.Generic;
public static class EnumExtension {
public static IEnumerable<(T item, int index)> WithIndex<T>(this IEnumerable<T> self)
=> self.Select((item, index) => (item, index));
}
Could do something like this:
public static class ForEachExtensions
{
public static void ForEachWithIndex<T>(this IEnumerable<T> enumerable, Action<T, int> handler)
{
int idx = 0;
foreach (T item in enumerable)
handler(item, idx++);
}
}
public class Example
{
public static void Main()
{
string[] values = new[] { "foo", "bar", "baz" };
values.ForEachWithIndex((item, idx) => Console.WriteLine("{0}: {1}", idx, item));
}
}
I disagree with comments that a for loop is a better choice in most cases.
foreach is a useful construct, and not replaceble by a for loop in all circumstances.
For example, if you have a DataReader and loop through all records using a foreach it automatically calls the Dispose method and closes the reader (which can then close the connection automatically). This is therefore safer as it prevents connection leaks even if you forget to close the reader.
(Sure it is good practise to always close readers but the compiler is not going to catch it if you don't - you can't guarantee you have closed all readers but you can make it more likely you won't leak connections by getting in the habit of using foreach.)
There may be other examples of the implicit call of the Dispose method being useful.
Literal Answer -- warning, performance may not be as good as just using an int to track the index. At least it is better than using IndexOf.
You just need to use the indexing overload of Select to wrap each item in the collection with an anonymous object that knows the index. This can be done against anything that implements IEnumerable.
System.Collections.IEnumerable collection = Enumerable.Range(100, 10);
foreach (var o in collection.OfType<object>().Select((x, i) => new {x, i}))
{
Console.WriteLine("{0} {1}", o.i, o.x);
}
Using LINQ, C# 7, and the System.ValueTuple NuGet package, you can do this:
foreach (var (value, index) in collection.Select((v, i)=>(v, i))) {
Console.WriteLine(value + " is at index " + index);
}
You can use the regular foreach construct and be able to access the value and index directly, not as a member of an object, and keeps both fields only in the scope of the loop. For these reasons, I believe this is the best solution if you are able to use C# 7 and System.ValueTuple.
There's nothing wrong with using a counter variable. In fact, whether you use for, foreach while or do, a counter variable must somewhere be declared and incremented.
So use this idiom if you're not sure if you have a suitably-indexed collection:
var i = 0;
foreach (var e in collection) {
// Do stuff with 'e' and 'i'
i++;
}
Else use this one if you know that your indexable collection is O(1) for index access (which it will be for Array and probably for List<T> (the documentation doesn't say), but not necessarily for other types (such as LinkedList)):
// Hope the JIT compiler optimises read of the 'Count' property!
for (var i = 0; i < collection.Count; i++) {
var e = collection[i];
// Do stuff with 'e' and 'i'
}
It should never be necessary to 'manually' operate the IEnumerator by invoking MoveNext() and interrogating Current - foreach is saving you that particular bother ... if you need to skip items, just use a continue in the body of the loop.
And just for completeness, depending on what you were doing with your index (the above constructs offer plenty of flexibility), you might use Parallel LINQ:
// First, filter 'e' based on 'i',
// then apply an action to remaining 'e'
collection
.AsParallel()
.Where((e,i) => /* filter with e,i */)
.ForAll(e => { /* use e, but don't modify it */ });
// Using 'e' and 'i', produce a new collection,
// where each element incorporates 'i'
collection
.AsParallel()
.Select((e, i) => new MyWrapper(e, i));
We use AsParallel() above, because it's 2014 already, and we want to make good use of those multiple cores to speed things up. Further, for 'sequential' LINQ, you only get a ForEach() extension method on List<T> and Array ... and it's not clear that using it is any better than doing a simple foreach, since you are still running single-threaded for uglier syntax.
Using #FlySwat's answer, I came up with this solution:
//var list = new List<int> { 1, 2, 3, 4, 5, 6 }; // Your sample collection
var listEnumerator = list.GetEnumerator(); // Get enumerator
for (var i = 0; listEnumerator.MoveNext() == true; i++)
{
int currentItem = listEnumerator.Current; // Get current item.
//Console.WriteLine("At index {0}, item is {1}", i, currentItem); // Do as you wish with i and currentItem
}
You get the enumerator using GetEnumerator and then you loop using a for loop. However, the trick is to make the loop's condition listEnumerator.MoveNext() == true.
Since the MoveNext method of an enumerator returns true if there is a next element and it can be accessed, making that the loop condition makes the loop stop when we run out of elements to iterate over.
Just add your own index. Keep it simple.
int i = -1;
foreach (var item in Collection)
{
++i;
item.index = i;
}
You could wrap the original enumerator with another that does contain the index information.
foreach (var item in ForEachHelper.WithIndex(collection))
{
Console.Write("Index=" + item.Index);
Console.Write(";Value= " + item.Value);
Console.Write(";IsLast=" + item.IsLast);
Console.WriteLine();
}
Here is the code for the ForEachHelper class.
public static class ForEachHelper
{
public sealed class Item<T>
{
public int Index { get; set; }
public T Value { get; set; }
public bool IsLast { get; set; }
}
public static IEnumerable<Item<T>> WithIndex<T>(IEnumerable<T> enumerable)
{
Item<T> item = null;
foreach (T value in enumerable)
{
Item<T> next = new Item<T>();
next.Index = 0;
next.Value = value;
next.IsLast = false;
if (item != null)
{
next.Index = item.Index + 1;
yield return item;
}
item = next;
}
if (item != null)
{
item.IsLast = true;
yield return item;
}
}
}
Why foreach ?!
The simplest way is using for instead of foreach if you are using List:
for (int i = 0 ; i < myList.Count ; i++)
{
// Do something...
}
Or if you want use foreach:
foreach (string m in myList)
{
// Do something...
}
You can use this to know the index of each loop:
myList.indexOf(m)
Here's a solution I just came up with for this problem
Original code:
int index=0;
foreach (var item in enumerable)
{
blah(item, index); // some code that depends on the index
index++;
}
Updated code
enumerable.ForEach((item, index) => blah(item, index));
Extension Method:
public static IEnumerable<T> ForEach<T>(this IEnumerable<T> enumerable, Action<T, int> action)
{
var unit = new Unit(); // unit is a new type from the reactive framework (http://msdn.microsoft.com/en-us/devlabs/ee794896.aspx) to represent a void, since in C# you can't return a void
enumerable.Select((item, i) =>
{
action(item, i);
return unit;
}).ToList();
return pSource;
}
C# 7 finally gives us an elegant way to do this:
static class Extensions
{
public static IEnumerable<(int, T)> Enumerate<T>(
this IEnumerable<T> input,
int start = 0
)
{
int i = start;
foreach (var t in input)
{
yield return (i++, t);
}
}
}
class Program
{
static void Main(string[] args)
{
var s = new string[]
{
"Alpha",
"Bravo",
"Charlie",
"Delta"
};
foreach (var (i, t) in s.Enumerate())
{
Console.WriteLine($"{i}: {t}");
}
}
}
This answer: lobby the C# language team for direct language support.
The leading answer states:
Obviously, the concept of an index is foreign to the concept of
enumeration, and cannot be done.
While this is true of the current C# language version (2020), this is not a conceptual CLR/Language limit, it can be done.
The Microsoft C# language development team could create a new C# language feature, by adding support for a new Interface IIndexedEnumerable
foreach (var item in collection with var index)
{
Console.WriteLine("Iteration {0} has value {1}", index, item);
}
//or, building on #user1414213562's answer
foreach (var (item, index) in collection)
{
Console.WriteLine("Iteration {0} has value {1}", index, item);
}
If foreach () is used and with var index is present, then the compiler expects the item collection to declare IIndexedEnumerable interface. If the interface is absent, the compiler can polyfill wrap the source with an IndexedEnumerable object, which adds in the code for tracking the index.
interface IIndexedEnumerable<T> : IEnumerable<T>
{
//Not index, because sometimes source IEnumerables are transient
public long IterationNumber { get; }
}
Later, the CLR can be updated to have internal index tracking, that is only used if with keyword is specified and the source doesn't directly implement IIndexedEnumerable
Why:
Foreach looks nicer, and in business applications, foreach loops are rarely a performance bottleneck
Foreach can be more efficient on memory. Having a pipeline of functions instead of converting to new collections at each step. Who cares if it uses a few more CPU cycles when there are fewer CPU cache faults and fewer garbage collections?
Requiring the coder to add index-tracking code, spoils the beauty
It's quite easy to implement (please Microsoft) and is backward compatible
While most people here are not Microsoft employees, this is a correct answer, you can lobby Microsoft to add such a feature. You could already build your own iterator with an extension function and use tuples, but Microsoft could sprinkle the syntactic sugar to avoid the extension function
It's only going to work for a List and not any IEnumerable, but in LINQ there's this:
IList<Object> collection = new List<Object> {
new Object(),
new Object(),
new Object(),
};
foreach (Object o in collection)
{
Console.WriteLine(collection.IndexOf(o));
}
Console.ReadLine();
#Jonathan I didn't say it was a great answer, I just said it was just showing it was possible to do what he asked :)
#Graphain I wouldn't expect it to be fast - I'm not entirely sure how it works, it could reiterate through the entire list each time to find a matching object, which would be a helluvalot of compares.
That said, List might keep an index of each object along with the count.
Jonathan seems to have a better idea, if he would elaborate?
It would be better to just keep a count of where you're up to in the foreach though, simpler, and more adaptable.
This is how I do it, which is nice for its simplicity/brevity, but if you're doing a lot in the loop body obj.Value, it is going to get old pretty fast.
foreach(var obj in collection.Select((item, index) => new { Index = index, Value = item }) {
string foo = string.Format("Something[{0}] = {1}", obj.Index, obj.Value);
...
}
int index;
foreach (Object o in collection)
{
index = collection.indexOf(o);
}
This would work for collections supporting IList.
// using foreach loop how to get index number:
foreach (var result in results.Select((value, index) => new { index, value }))
{
// do something
}
Better to use keyword continue safe construction like this
int i=-1;
foreach (Object o in collection)
{
++i;
//...
continue; //<--- safe to call, index will be increased
//...
}
You can write your loop like this:
var s = "ABCDEFG";
foreach (var item in s.GetEnumeratorWithIndex())
{
System.Console.WriteLine("Character: {0}, Position: {1}", item.Value, item.Index);
}
After adding the following struct and extension method.
The struct and extension method encapsulate Enumerable.Select functionality.
public struct ValueWithIndex<T>
{
public readonly T Value;
public readonly int Index;
public ValueWithIndex(T value, int index)
{
this.Value = value;
this.Index = index;
}
public static ValueWithIndex<T> Create(T value, int index)
{
return new ValueWithIndex<T>(value, index);
}
}
public static class ExtensionMethods
{
public static IEnumerable<ValueWithIndex<T>> GetEnumeratorWithIndex<T>(this IEnumerable<T> enumerable)
{
return enumerable.Select(ValueWithIndex<T>.Create);
}
}
If the collection is a list, you can use List.IndexOf, as in:
foreach (Object o in collection)
{
// ...
#collection.IndexOf(o)
}
This way you can use the index and value using LINQ:
ListValues.Select((x, i) => new { Value = x, Index = i }).ToList().ForEach(element =>
{
// element.Index
// element.Value
});
My solution for this problem is an extension method WithIndex(),
http://code.google.com/p/ub-dotnet-utilities/source/browse/trunk/Src/Utilities/Extensions/EnumerableExtensions.cs
Use it like
var list = new List<int> { 1, 2, 3, 4, 5, 6 };
var odd = list.WithIndex().Where(i => (i.Item & 1) == 1);
CollectionAssert.AreEqual(new[] { 0, 2, 4 }, odd.Select(i => i.Index));
CollectionAssert.AreEqual(new[] { 1, 3, 5 }, odd.Select(i => i.Item));
For interest, Phil Haack just wrote an example of this in the context of a Razor Templated Delegate (http://haacked.com/archive/2011/04/14/a-better-razor-foreach-loop.aspx)
Effectively he writes an extension method which wraps the iteration in an "IteratedItem" class (see below) allowing access to the index as well as the element during iteration.
public class IndexedItem<TModel> {
public IndexedItem(int index, TModel item) {
Index = index;
Item = item;
}
public int Index { get; private set; }
public TModel Item { get; private set; }
}
However, while this would be fine in a non-Razor environment if you are doing a single operation (i.e. one that could be provided as a lambda) it's not going to be a solid replacement of the for/foreach syntax in non-Razor contexts.
I don't think this should be quite efficient, but it works:
#foreach (var banner in Model.MainBanners) {
#Model.MainBanners.IndexOf(banner)
}
I built this in LINQPad:
var listOfNames = new List<string>(){"John","Steve","Anna","Chris"};
var listCount = listOfNames.Count;
var NamesWithCommas = string.Empty;
foreach (var element in listOfNames)
{
NamesWithCommas += element;
if(listOfNames.IndexOf(element) != listCount -1)
{
NamesWithCommas += ", ";
}
}
NamesWithCommas.Dump(); //LINQPad method to write to console.
You could also just use string.join:
var joinResult = string.Join(",", listOfNames);
I don't believe there is a way to get the value of the current iteration of a foreach loop. Counting yourself, seems to be the best way.
May I ask, why you would want to know?
It seems that you would most likley be doing one of three things:
1) Getting the object from the collection, but in this case you already have it.
2) Counting the objects for later post processing...the collections have a Count property that you could make use of.
3) Setting a property on the object based on its order in the loop...although you could easily be setting that when you added the object to the collection.
Unless your collection can return the index of the object via some method, the only way is to use a counter like in your example.
However, when working with indexes, the only reasonable answer to the problem is to use a for loop. Anything else introduces code complexity, not to mention time and space complexity.
I just had this problem, but thinking around the problem in my case gave the best solution, unrelated to the expected solution.
It could be quite a common case, basically, I'm reading from one source list and creating objects based on them in a destination list, however, I have to check whether the source items are valid first and want to return the row of any error. At first-glance, I want to get the index into the enumerator of the object at the Current property, however, as I am copying these elements, I implicitly know the current index anyway from the current destination. Obviously it depends on your destination object, but for me it was a List, and most likely it will implement ICollection.
i.e.
var destinationList = new List<someObject>();
foreach (var item in itemList)
{
var stringArray = item.Split(new char[] { ';', ',' }, StringSplitOptions.RemoveEmptyEntries);
if (stringArray.Length != 2)
{
//use the destinationList Count property to give us the index into the stringArray list
throw new Exception("Item at row " + (destinationList.Count + 1) + " has a problem.");
}
else
{
destinationList.Add(new someObject() { Prop1 = stringArray[0], Prop2 = stringArray[1]});
}
}
Not always applicable, but often enough to be worth mentioning, I think.
Anyway, the point being that sometimes there is a non-obvious solution already in the logic you have...

Categories