"for loop" for ValueCollection - c#

Is there a way to iterate ValueCollection using straight for loop? (not foreach)
e.g.
Dictionary<string, List<long>>.ValueCollection somevalues = somecollection.Value.Values;
for(int i = 0; i< somevalues.Count; i++)
{
//now what?
}

No - there's no indexer or anything similar for ValueCollection. I suppose you could use:
for (int i = 0; i < someValues.Count; i++)
{
var item = someValues.ElementAt(i);
...
}
but that would perform like a dog :) (Just iteration would be O(n^2), as it would be like Schlemiel the Painter.)
Why do you want to do this? If you want items with elements, just keep a counter or use the overload of Select that passes in the index as well as the item.

You don't have to use an index in a for loop...
for (var en = somevalues.GetEnumerator(); en.MoveNext(); )
{
var item = en.Current;
// do something useful...
}

not out of the box. some collections do not have index operators ( myCollection[ someIndex ] )

Your most likely reason for wanting this is to be able to use that index in some other way. Simply stick with a foreach loop, initialize a variable to zero before the loop and increment it at the bottom of the loop.

Related

Best way access element in an IEnumerable type

The language I use is C#.
Say we have a IEnumerable, which is the result of a linq query. T is an anonymous type.
What is the best way if we want to access the elements of this type.
I think that there are two ways.
1) Convert the IEnumerable to List and then access the elements.
List<T> list = result.ToList();
for(int rowIndex=0; rowIndex<list.Count; rowIndex++)
{
double x = list[rowIndex].val;
}
2)
for(int rowIndex=0; rowIndex<result.Count(); rowIndex++)
{
double x = result.ElementAt(rowIndex).val;
}
The reason why I am thinking something like the above is that except from accessing the elements of the IEnumerable, I need their indices. In other words, if an element is the first, the second etc.
Thanks in advance for any help !
You don't need to create collection, use an int variable which is 0 and increase it in a foreach. Then you have the index and the element.
int index = 0;
foreach(var x in result)
{
// x is the element and index the current index
Console.WriteLine("Val:{0} Index:{1}", x.val, index);
index ++;
}

How to get the size of arrays packed as value in a Dictionary<K,V> in C#?

I have a Dictionary<K,V> object already filled with data:
Dictionary<string, double[]> ltableData;
Every double[] has the same size (number of elements).
I do not know in advance neither any 'string' key nor the size of the 'double[]' values.
Now I have to make one cycle with a nested one as follows:
for(int i = 0; i< number_elements;i++)
{
foreach (var array in ltableData.Values)
{
ltempList.Add(array[i]);
//other instructions
}
}
How can I assign number_elements? I can of course use this solution:
var lrowCount;
foreach(var item in ltableData.Values)
{
lrowCount = item.Count();
}
that works but it is of course ugly both to see and execute. Is there any cleaner and more effective method to extract the count? Thanks
Francesco
var lrowCount = ltableData.Values.First().Length;
// or
var lrowCount = ltableData.First().Value.Length;
foreach (var array in ltableData.Values)
{
for (int i = 0; i < array.Length; i++)
{
//other instructions
}
}
or, even more readable,
foreach (var array in ltableData.Values)
{
foreach (var val in array)
{
//other instructions
}
}
You can take its length from any item:
int number_elements = ltableData.Values.Select(v => v.Length).FirstOrDefault();
Though I think if you have such structure then you should create a class for it which will have a Length on top level and which will also assert and guarantee that all inner items have the same length.
If you know that itableData does contain values you can do the following.
ltableData.Values.First().Count();
I'm not going to say this is much cleaner, but you could do
var number_elements = ltableData.Values.First().Count();
This is ONLY if you must need the length. Otherwise, a foreach loop would be just fine.
Now that you've clarified what you're doing as per the comments on your original post, it's clear that you actually want
using System.Linq;
var ltempList = ltableData.SelectMany(kvp => kvp.Value);
This will give an IEnumerable<double> containing all of the values from all different entries in the dictionary, aggregated together.
you can use this to get the total number of values
var number_elements = ltableData.Select(p => p.Value.Count()).Sum();

modify a list while doing foreach inside lock()

atm I do it like this:
lock (LockObj)
{
foreach (var o in Oo)
{
var val = o.DateActive;
if (val.AddSeconds(30) < DateTime.Now) Oo.Remove(o);
}
}
and I get this error:
Collection was modified; enumeration operation may not execute
how this should be done?
You have to use a regular for loop.
for (int i = 0; i < Oo.Length; ++i)
{
var val = Oo[i];
if (val.AddSeconds(30) < DateTime.Now)
{
Oo.RemoveAt(i);
i--; // since we just removed an element
}
}
The reason you cannot edit a collection with a foreach loop is because foreach uses a readonly IEnumerator of the collection you are iterating.
you can't modify a collection you are enumerating..
to change it get a copy of it and change it.
for(var k in OO.ToList())
.....
or
use count and iterate the collection with index,
for (int i=0;i<OO.Count();i++)
.....
You simply cannot modify the collection if you are iterating with foreach. You have two options, Loop with For instead of foreach or create another Collection and modify that.
This problem is completely unrelated to locking.
If you add/remove elements from a List all iterators pointing to that list become invalid.
One alternative to using an iterator is manually working with indices. Then you can iterate backwards and remove elements with RemoveAt.
for(int i=Oo.Count-1;i>=0;i--)
{
var o=Oo[i];
if (o.DateActive.AddSeconds(30)<DateTime.Now)
Oo.RemoveAt(i);
}
Unfortunately this native implementation is O(n^2). If you write it in a more complex way where you first assign the elements to their new position and then truncate the list it becomes O(n).
Buf if Oo is a List<T> there is a much better solution. You can use Oo.RemoveAll(o=>o.DateActive.AddSeconds(30)<DateTime.Now). Unfortunately you there is no such extension method on IList<T> by default.
I'd write the code like this:
lock (LockObj)
{
DateTime deleteTime=DateTime.Now.AddSeconds(-30);
Oo.RemoveAll(o=>o.DateActive<deleteTime);
}
As a sidenote I'd personally use UTC times instead of local times for such code.
class Program
{
static void Main(string[] args)
{
List<OOItem> oo = new List<OOItem>();
oo.Add( new OOItem() { DateActive = DateTime.Now.AddSeconds(-31) });
lock(LockObj)
{
foreach( var item in oo.Where( ooItem => ooItem.DateActive.AddSeconds(30) < DateTime.Now ).ToArray())
{
oo.Remove(item);
}
}
Debug.Assert( oo.Count == 0);
}
}
public class OOItem
{
public DateTime DateActive { get; set; }
}
I'm going to suggest an approach that avoids messing around with decrementing loop indexes and other stuff that makes code difficult to understand.
I think the best bet is to write a nice query and then do a foreach over the result of turning the query into an array:
var inactives = from o in Oo
where o.DateActive < DateTime.Now
select o;
foreach (var o in inactives.ToArray())
{
Oo.Remove(o);
}
This avoids the issue of the collection changing and makes the code quite a bit more readable.
If you're a little more "functionally" oriented then here's another choice:
(from o in Oo
where o.DateActive < DateTime.Now
select o)
.ToList()
.ForEach(o => Oo.Remove(o));
Enjoy!
The problem is not related to the lock.
Use a for() loop instead of foreach().
I can't 100% replace your code because your code provides no hint of what collection type "Oo" is. Neither does the name "Oo". Perhaps one of the evils of var keyword overuse? Or maybe I just can't see enough of your code ;)
int size = Oo.Length();
for(int i = 0; i < size; i++){
if (Oo[i].AddSeconds(30) < DateTime.Now){
Oo[i].RemoveAt(i);
size--; // Compensate for new size after removal.
}
}
you can use Parallel.ForEach(oO, val=> { oO.Remove(val); })
Parallel doesn't have the IEnumerator problem !

how to access a string array outside loop

for (int z = 0; z < alParmValues.Count; z++)
{
//string[] def;
string[] asd = alParmValues[z].ToString().Split(',');//this is of type string.collections and u cant cast it to a arraylist or array
//if (HUTT.clsParameterValues.bCustomObj == false)
string[] def = alMethSign[z].ToString().Substring(alMethSign[z].ToString().IndexOf('(') + 1, alMethSign[z].ToString().IndexOf(')') - (alMethSign[z].ToString().IndexOf('(') + 1)).Split(',');
}
I have to access both the string arrays outside the loop. Is there a better solution to this? I can't use an ArrayList or declare them as public so how can I access them?
To access something outside of a loop, just declare it outside of the loop, then work with it after your loop processing is done:
string[] arr = ...
for (int z = 0; z < alParmValues.Count; z++)
{
// work with arr...
}
var item = arr[3]; // Accessed outside of loop.
However, there seem to be a few things wrong with your code. I'd recommend thinking a little bit more about the loop body and what you're trying to do there. Consider this line, for example:
for (int z = 0; z < alParmValues.Count; z++)
{
// ...
string[] asd = alParmValues[z].ToString().Split(',');
// There aren't any more references to asd after this point in the loop,
// so this assignment serves no purpose and only keeps its last assigned
// value.
}
This assignment is pointless; every time you go through the loop, you just overwrite the previous value of asd, and you never use it later in the loop.
The scope of both asd and def are limited to the body of the for loop. If you have to access them you need to declare them outside the loop. Is there a problem in putting them out?
Take a look at the Collection Classes Tutorial on MSDN.
Both 'asd' and 'def' are string arrays whose scope is limited to the for loop. You cannot access them outside the loop. If you want to do so, try declaring them outside the for loop.
First, if you want access to the data extracted/computed inside the loop, you must declare a container for the results outside the loop, and then populate its values inside the loop.
Second, don't think about casting the arrays returned from the split method, but rather think about processing their contents.
Assuming that you want the combined results from all elements of the original alParmValues array in a single pair of results, I'd use something like the following pseudo-code. Of course, you'll need to fill in the type for your alParmValues and alMethSign elements, add semicolons, etc. (Because your question didn't explain the content and relationships between the two arrays being processed in your loop, I've just treated them independently.) This isn't complete code, but just a sketch to get you started:
ArrayList allValues = new ArrayList()
foreach (??? parameter in alParmValues) {
foreach (String value in parameter.ToString().Split(',')) {
allValues.add(value)
}
}
ArrayList allMethSignValues = new ArrayList()
foreach (??? methSign in alMethSign) {
String thisString = methSign.toString()
int open = thisString.indexOf('(')
int close = thisString.indexOf(')')
String parenPart = thisString.substring(open + 1, close - open - 1)
foreach (String value in parenPart.split(',')) {
allMethSignValues.add(value)
}
}

What is the best way to iterate through a strongly-typed generic List<T>?

What is the best way to iterate through a strongly-typed generic List in C#.NET and VB.NET?
For C#:
foreach(ObjectType objectItem in objectTypeList)
{
// ...do some stuff
}
Answer for VB.NET from Purple Ant:
For Each objectItem as ObjectType in objectTypeList
'Do some stuff '
Next
With any generic implementation of IEnumerable the best way is:
//C#
foreach( var item in listVariable) {
//do stuff
}
There is an important exception however. IEnumerable involves an overhead of Current() and MoveNext() that is what the foreach loop is actually compiled into.
When you have a simple array of structs:
//C#
int[] valueTypeArray;
for(int i=0; i < valueTypeArray.Length; ++i) {
int item = valueTypeArray[i];
//do stuff
}
Is quicker.
Update
Following a discussion with #Steven Sudit (see comments) I think my original advice may be out of date or mistaken, so I ran some tests:
// create a list to test with
var theList = Enumerable.Range(0, 100000000).ToList();
// time foreach
var sw = Stopwatch.StartNew();
foreach (var item in theList)
{
int inLoop = item;
}
Console.WriteLine("list foreach: " + sw.Elapsed.ToString());
sw.Reset();
sw.Start();
// time for
int cnt = theList.Count;
for (int i = 0; i < cnt; i++)
{
int inLoop = theList[i];
}
Console.WriteLine("list for : " + sw.Elapsed.ToString());
// now run the same tests, but with an array
var theArray = theList.ToArray();
sw.Reset();
sw.Start();
foreach (var item in theArray)
{
int inLoop = item;
}
Console.WriteLine("array foreach: " + sw.Elapsed.ToString());
sw.Reset();
sw.Start();
// time for
cnt = theArray.Length;
for (int i = 0; i < cnt; i++)
{
int inLoop = theArray[i];
}
Console.WriteLine("array for : " + sw.Elapsed.ToString());
Console.ReadKey();
So, I ran this in release with all optimisations:
list foreach: 00:00:00.5137506
list for : 00:00:00.2417709
array foreach: 00:00:00.1085653
array for : 00:00:00.0954890
And then debug without optimisations:
list foreach: 00:00:01.1289015
list for : 00:00:00.9945345
array foreach: 00:00:00.6405422
array for : 00:00:00.4913245
So it appears fairly consistent, for is quicker than foreach and arrays are quicker than generic lists.
However, this is across 100,000,000 iterations and the difference is about .4 of a second between the fastest and slowest methods. Unless you're doing massive performance critical loops it just isn't worth worrying about.
C#
myList<string>().ForEach(
delegate(string name)
{
Console.WriteLine(name);
});
Anonymous delegates are not currently implemented in VB.Net, but both C# and VB.Net should be able to do lambdas:
C#
myList<string>().ForEach(name => Console.WriteLine(name));
VB.Net
myList(Of String)().ForEach(Function(name) Console.WriteLine(name))
As Grauenwolf pointed out the above VB won't compile since the lambda doesn't return a value. A normal ForEach loop as others have suggested is probably the easiest for now, but as usual it takes a block of code to do what C# can do in one line.
Here's a trite example of why this might be useful: this gives you the ability to pass in the loop logic from another scope than where the IEnumerable exists, so you don't even have to expose it if you don't want to.
Say you have a list of relative url paths that you want to make absolute:
public IEnumerable<String> Paths(Func<String> formatter) {
List<String> paths = new List<String>()
{
"/about", "/contact", "/services"
};
return paths.ForEach(formatter);
}
So then you could call the function this way:
var hostname = "myhost.com";
var formatter = f => String.Format("http://{0}{1}", hostname, f);
IEnumerable<String> absolutePaths = Paths(formatter);
Giving you "http://myhost.com/about", "http://myhost.com/contact" etc. Obviously there are better ways to accomplish this in this specfic example, I'm just trying to demonstrate the basic principle.
For VB.NET:
For Each tmpObject as ObjectType in ObjectTypeList
'Do some stuff '
Next
Without knowing the internal implementation of a list, I think generally the best way to iterate over it would be a foreach loop. Because foreach uses an IEnumerator to walk over the list, it's up to the list itself to determine how to move from object to object.
If the internal implementation was, say, a linked list, then a simple for loop would be quite a bit slower than a foreach.
Does that make sense?
It depends on your application:
for loop, if efficiency is a priority
foreach loop or ForEach method, whichever communicates your intent more clearly
I may be missing something, but iterating through a generic list should be fairly simple if you use my examples below. The List<> class implements the IList and IEnumerable interfaces so that you can easily iterate through them basically any way you want.
The most efficient way would be to use a for loop:
for(int i = 0; i < genericList.Count; ++i)
{
// Loop body
}
You may also choose to use a foreach loop:
foreach(<insertTypeHere> o in genericList)
{
// Loop body
}

Categories

Resources