Iterating over a list and altering it?

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

I am a C++ programmer and have been learning C#. I have constructed a List<>
and I want to iterate over it, altering each string in the list.

In C++, I'd just create an iterator and walk the list, so I was looking for
something similar in C#. I looked at foreach, List.ForEach, and IEnumerator.
The problem is that all of them seem to return readonly pointers to the
items in the List. Therefore I can't alter the list. So I'm using a for
loop, but ... I'm just baffled that there aren't any sort of iterators that
let me alter the list. I have the feeling that there are, or that I'm just
not using these right. So I figured I'd ask!

Here's some of the code I tried ... note that udLine is a struct, and udList
is a List of those structs.
public List<udLine> udList = new List<udLine>(100);

IEnumerator<udLine> enumerator = udList.GetEnumerator();
while (enumerator.MoveNext())
{
enumerator.Current.header =
enumerator.Current.header.PadLeft(LongestHeaderLength);
}


I really was curious to try this:
public void AlterItem(udLine ud)
{
ud.header = ud.header.PadLeft(LongestHeaderLength);
}

and then call:
udList.ForEach(AlterItem);

but nothing happened. My guess was that the ud was getting copied, so I
made it a ref argument:
public void AlterItem(ref udLine ud)
{
ud.header = ud.header.PadLeft(LongestHeaderLength);
}

udList.ForEach(ref AlterItem);

but the compiler really didn't like that.

So I'm using a for loop. But is there a way to make either of the above
statments work?

Thank you!
 
OK - you started talking strings, and ended with structs... I think
you need to clarify:

are you a: trying to change the actual contents of the list (i.e. swap
items with replacements), or b: update properties of items that are in
the list?

if "b" then a foreach loop is fine, but the problem here may be that
you are using structures not classes; because these are value-typed
they are going to get copied left right and centre. First rule: .Net
structs should be immutable unless you really, really know what you
are doing. That means that you have to switch to scenario "a".

Now; for "a", note that changing the contents of the list (meaning:
adding, removing, swapping, etc) breaks iterators. This is
intentional. For this scenario the common solution is to use indexer
syntax instead:

for( int i = 0 ; i < list.count ; i++ ) {
list = theNewValuePerhapsFromTheOldValue();
}

Hope this helps,

Marc
 
In addition to what Marc said, strings are _immutable_ reference type
in .NET so they behave like structs in terms of altering list elements
-- you have to reassign the element in question, ergo you can't use
iterators which are read-only with respect to the list.
 
Sorry, Marc - I started with a simplified question for clarity and then
forgot my simplification. I have a list of structs. Most of the structs are
strings, and I'm trying to alter one of the strings in each struct.

It sounds like I ended up with the right answer in the end, with the for
loop. I take it that the ForEach concept is more to get the data out and put
it somewhere else than to operate on the data itself?
 
OK - you started talking strings, and ended with structs... I think
you need to clarify:

are you a: trying to change the actual contents of the list (i.e. swap
items with replacements), or b: update properties of items that are in
the list?

if "b" then a foreach loop is fine, but the problem here may be that
you are using structures not classes; because these are value-typed
they are going to get copied left right and centre. First rule: .Net
structs should be immutable unless you really, really know what you
are doing. That means that you have to switch to scenario "a".

Now; for "a", note that changing the contents of the list (meaning:
adding, removing, swapping, etc) breaks iterators. This is
intentional. For this scenario the common solution is to use indexer
syntax instead:

for( int i = 0 ; i < list.count ; i++ ) {
list = theNewValuePerhapsFromTheOldValue();

}

Hope this helps,

Marc


I have to disagree that structs should be immutable in .NET - most of
the internal structs provided by .NET are not immutable... in fact,
you'll find more classes are immutable than structs. In general, the
approach is that, if you want a class that you can pass around to lots
of objects, it should be immutable - that avoids the terrifying
headache of aliasing (eg: fonts, strings, etc.). So really, you have
it the other way around - if you want a class that will be used like a
struct, make it immutable. Structs avoid aliasing automatically,
since they're always copy. Personally, I think the important thing is
to always KNOW that a struct is a struct - if you have to include the
word "struct" in it's name, that's fine (since intellisense leaves out
this freakishly crucial piece of information).

Immutable structs defeat most of the advantages of using structs, and
the compiler is sufficiently smart to catch most of the stupid crap
you can get in trouble doing with a struct (IE changing values on a
temporary that will be dropped). Besides, in most DotNet languages,
immutables are a headache to implement (sixteen billion hand-coded
constructors).
 
I am a C++ programmer and have been learning C#. I have constructed a List<>
and I want to iterate over it, altering each string in the list.

In C++, I'd just create an iterator and walk the list, so I was looking for
something similar in C#. I looked at foreach, List.ForEach, and IEnumerator.
The problem is that all of them seem to return readonly pointers to the
items in the List. Therefore I can't alter the list. So I'm using a for
loop, but ... I'm just baffled that there aren't any sort of iterators that
let me alter the list. I have the feeling that there are, or that I'm just
not using these right. So I figured I'd ask!

Here's some of the code I tried ... note that udLine is a struct, and udList
is a List of those structs.
public List<udLine> udList = new List<udLine>(100);

IEnumerator<udLine> enumerator = udList.GetEnumerator();
while (enumerator.MoveNext())
{
enumerator.Current.header =
enumerator.Current.header.PadLeft(LongestHeaderLength);
}

I really was curious to try this:
public void AlterItem(udLine ud)
{
ud.header = ud.header.PadLeft(LongestHeaderLength);
}

and then call:
udList.ForEach(AlterItem);

but nothing happened. My guess was that the ud was getting copied, so I
made it a ref argument:
public void AlterItem(ref udLine ud)
{
ud.header = ud.header.PadLeft(LongestHeaderLength);
}

udList.ForEach(ref AlterItem);

but the compiler really didn't like that.

So I'm using a for loop. But is there a way to make either of the above
statments work?

Is there a particular reason why you chose to make udLine a struct
rather than a class? Note that these two keywords have much more
significant implications in C# than in C++.

I suggest that you make udLine a class. Then there will be no need to
pass it using "ref", and your problem should disppear.
 
Evan said:
Sorry, Marc - I started with a simplified question for clarity and then
forgot my simplification. I have a list of structs. Most of the structs are
strings, and I'm trying to alter one of the strings in each struct.

It sounds like I ended up with the right answer in the end, with the for
loop. I take it that the ForEach concept is more to get the data out and put
it somewhere else than to operate on the data itself?

Just make it a class instead of a struct, and you can change the members
of the class without problem.
 
Martin said:
I have to disagree that structs should be immutable in .NET - most of
the internal structs provided by .NET are not immutable... in fact,
you'll find more classes are immutable than structs.

I haven't made a count so I can't say that you are wrong, but I find
that many of the most common structures are immutable, like for example
Color, DateTime, Decimal and TimeSpan. All built-in basic types, like
Int32 and Double, are of course also immutable.

I know of only a few that actually are mutable, like Point, Size and
Rect, and it has been widely debated if making them mutable was a good
move or not.
In general, the
approach is that, if you want a class that you can pass around to lots
of objects, it should be immutable - that avoids the terrifying
headache of aliasing (eg: fonts, strings, etc.). So really, you have
it the other way around - if you want a class that will be used like a
struct, make it immutable. Structs avoid aliasing automatically,
since they're always copy. Personally, I think the important thing is
to always KNOW that a struct is a struct - if you have to include the
word "struct" in it's name, that's fine (since intellisense leaves out
this freakishly crucial piece of information).

Immutable structs defeat most of the advantages of using structs,

Then I am not convinced that you are using structures the way that they
are intended.

If you are using structures as if they were classes, then it would of
course make no sense to make them immutable. On the other hand, in that
case it doesn't really make sense to make them structures either.
and
the compiler is sufficiently smart to catch most of the stupid crap
you can get in trouble doing with a struct (IE changing values on a
temporary that will be dropped). Besides, in most DotNet languages,
immutables are a headache to implement (sixteen billion hand-coded
constructors).

I rarely find that a structure would need more than a few constructors.
With the limited size that is recommneded for structures, there can't be
so many different ways of creating them.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Back
Top