Retrieving datas from an ArrayList filled with another ArrayList - c#

I got 2 ArrayList objects on my project defined as
ArrayList final_list = new ArrayList();
ArrayList temp_list = new ArrayList();
I needed to fill my final_list with the other one, so I used a loop using final_list.Add(temp_list) inside of it, which works fine.
Here is an exemple about what my final_listobject looks like after the loop :
The fact is I need to process the datas after the loop. So I guess I'll have to do something like
for (int i = 0; i < final_list.Count; i++)
{
for (int j = 0; j < 6 ; j++)
{
// Retrieving my [0,0] , [0,1], ... , [final_list.Count,5] datas
}
}
but this isn't working.
Anyway, I'm even struggling on the correct syntax to use so I already tried hard coded things like final_list[0,1] or final_list[0][1]to display the 10 value for exemple, but it doesn't work.
How can I manage to do that ?

Seems you have a collection (final_list), which contains some collections inside. And now you want to process the inner most elements.
First of all, you'd better use generic collections instead of old ArrayList.
Generally, handling such a scenario can be done like this:
foreach( List<string> innerList in final_list)
{
foreach( var innerMostItem in innerList)
{
// process the element!
}
}
or equivelantely:
foreach( var innerList in final_list)
{
foreach( var innerMostItem in innerList as List<string>)
{
// process the element!
}
}
By the way, naming convention of C#, is to use camelCase for variables.
update
code snippet above is updated. Not the type casting in the inner loop!
Though innerList was originally an IEnumerable, it is retrieved from the final_list as an instance of object class. You need to explicitly cast it to ArrayList or you will get an exception.

Related

C# Foreach Loop Doesn't Exit Properly [duplicate]

For now, the best I could think of is:
bool oneMoreTime = true;
while (oneMoreTime)
{
ItemType toDelete=null;
oneMoreTime=false;
foreach (ItemType item in collection)
{
if (ShouldBeDeleted(item))
{
toDelete=item;
break;
}
}
if (toDelete!=null)
{
collection.Remove(toDelete);
oneMoreTime=true;
}
}
I know that I have at least one extra variable here, but I included it to improve the readability of the algorithm.
The "RemoveAll" method is best.
Another common technique is:
var itemsToBeDeleted = collection.Where(i=>ShouldBeDeleted(i)).ToList();
foreach(var itemToBeDeleted in itemsToBeDeleted)
collection.Remove(itemToBeDeleted);
Another common technique is to use a "for" loop, but make sure you go backwards:
for (int i = collection.Count - 1; i >= 0; --i)
if (ShouldBeDeleted(collection[i]))
collection.RemoveAt(i);
Another common technique is to add the items that are not being removed to a new collection:
var newCollection = new List<whatever>();
foreach(var item in collection.Where(i=>!ShouldBeDeleted(i))
newCollection.Add(item);
And now you have two collections. A technique I particularly like if you want to end up with two collections is to use immutable data structures. With an immutable data structure, "removing" an item does not change the data structure; it gives you back a new data structure (that re-uses bits from the old one, if possible) that does not have the item you removed. With immutable data structures you are not modifying the thing you're iterating over, so there's no problem:
var newCollection = oldCollection;
foreach(var item in oldCollection.Where(i=>ShouldBeDeleted(i))
newCollection = newCollection.Remove(item);
or
var newCollection = ImmutableCollection<whatever>.Empty;
foreach(var item in oldCollection.Where(i=>!ShouldBeDeleted(i))
newCollection = newCollection.Add(item);
And when you're done, you have two collections. The new one has the items removed, the old one is the same as it ever was.
Just as I finished typing I remembered that there is lambda-way to do it.
collection.RemoveAll(i=>ShouldBeDeleted(i));
Better way?
A forward variation on the backward for loop:
for (int i = 0; i < collection.Count; )
if (ShouldBeDeleted(collection[i]))
collection.RemoveAt(i)
else
i++;
You cannot delete from a collection inside a foreach loop (unless it is a very special collection having a special enumerator). The BCL collections will throw exceptions if the collection is modified while it is being enumerated.
You could use a for loop to delete individual elements and adjust the index accordingly. However, doing that can be error prone. Depending on the implementation of the underlying collection it may also be expensive to delete individual elements. For instance deleting the first element of a List<T> will copy all the remaning elements in the list.
The best solution is often to create a new collection based on the old:
var newCollection = collection.Where(item => !ShouldBeDeleted(item)).ToList();
Use ToList() or ToArray() to create the new collection or initialize your specific collection type from the IEnumerable returned by the Where() clause.
The lambda way is good. You could also use a regular for loop, you can iterate lists that a for loop uses within the loop itself, unlike a foreach loop.
for (int i = collection.Count-1; i >= 0; i--)
{
if(ShouldBeDeleted(collection[i])
collection.RemoveAt(i);
}
I am assuming that collection is an arraylist here, the code might be a bit different if you are using a different data structure.

Create an object out of an array

Perhaps I didn't explaine myself the first time around so here is my second go at it.
I need to declare objects from a list of strings inside an array.
So my array goes out to a DB and collects the names from one colums. This names will all be an object. Now I want to define each object with that name fromt he column dynamicly.
So the array has say 5 elements in it of type string.
So going though my for look i cannot seem t o dynamicly create the object.
So instead of manually going myobject test = new myobject();
I just want to declare it by looping though the array.
I'am not pretty sure what your question is, but if I see your code than you want to create objects in your array?
Maybe this is your solution:
MyObject[] myArray = new MyObject[4];
for (int i =0; i < myArray.Length; ++)
{
myArray[i] = new MyObject();
}
Hope this will help you.
MyObject[] myArray = new MyObject[3];
for (int i =0; i < myArray.Length; i++)
{
MyObject obj = new MyObject();
myArray[i] = obj;
}
You can convert an array to objects by using System.Linq's select operator. You create an object for every i in the array and return a new object for it like this
var array = new string[2]{"one","two"};
var objects = array.Select(i=> new Object{Name = array[i]}).ToArray();

Cannot add items to an IList/List being casted from an IEnumerable

I'm trying to create a small proof-of-concept application for my boss, however the code I've created that simulates what he's trying to pull off isn't working.
for (int i = 0; i < 5000; i++)
{
((IList<string>) obj2.Stuff).Add("Iteration " + i.ToString());
}
I'm trying to pull this off all in one line because this is what his code looked like the other day in the framework we're working on. Anywho when the code above executes, I get a runtime error saying "Collection was of a fixed-size". And when I try casting to a List instead of an IList, I get an InvalidCastException saying "Unable to cast object of type 'System.String[]' to type 'System.Collections.Generic.List`1[System.String]'."
Anybody have any ideas on how I can pull off a single-line cast to add an item to the IEnumerable or help me figure out a way around the two errors I keep getting? Thanks in advance.
EDIT (4/19/2011 10:49AM EST)
I'm adding more code to help people out -- probably should've done this earlier. Sorry.
Program.cs:
#region Cast Test
Class1 obj2 = new Class1();
obj2.Stuff = Enumerable.Empty<string>();
Console.WriteLine("Cast - Start Time: " + 0 + "ms");
Stopwatch stopwatch2 = new Stopwatch();
stopwatch.Start();
for (int i = 0; i < 5000; i++)
{
((IList<string>) obj2.Stuff).Add("Iteration " + i.ToString());
}
stopwatch2.Stop();
Console.WriteLine("Cast - Stop Time: " + stopwatch2.ElapsedMilliseconds.ToString() + "ms");
#endregion
Class1.cs:
public class Class1
{
private IEnumerable<string> stuff;
public IEnumerable<string> Stuff
{
get { return stuff; }
set { stuff = value; }
}
}
Arrays in C# are of fixed size. You can't add items to them.
You cannot cast a string[] to IList<string> because string[] does not implement that interface. You will need to create an object implementing IList<string> first:
List<string> list = obj2.Stuff.ToList();
for (int i = 0; i < 5000; i++)
{
list.Add("Iteration " + i.ToString());
}
Why cast inside the for loop? While every IList is an IEnumerable, not every IEnumerable is an IList. You can use the ToList extention method to copy the IEnumerable to a new List. (Just be sure to be using System.Linq;)
Also, in this example, there is no need for a for loop:
var list = obj2.Stuff.ToList();
new list.AddRange(Enumerable.Range(0, 5000).Select(i => "Iteration " + i.ToString()));
In comments on one of the answers above you say "I'm trying to avoid copying the list."
You are trying to add data to an object whose underlying type is IEnumerable<T>. But an IEnumerable object is not an actual container, it's an interface. You can't add stuff to an interface. But you can assign another object that implements that interface to it.
So to use foson's example above, you could just do:
obj2.Stuff = Enumerable.Range(0, 5000).Select(i => "Iteration " + i.ToString());
Note that when this code executes, nothing actually happens. No objects will be created until something actually iterates over obj2.Stuff. When that happens, the methods in LINQ will be called that create objects one at a time and return them to the iterator loop.
But there's no actual storage device involved here. You can iterate over obj2.Stuff and unless you consequently added each integer to something else, they would be gone at the next iteration.
The fundamental point here is you can't store things in IEnumerable, rather, IEnumerable is a way to return objects in sequence, and that could be from a list construct, or from a function that generates a sequence.
You can't call Add since obj2.Stuff seems to be an array, and an array has a fixed size, as the error message indicates.
The type System.String[] is an array of strings, which implements IEnumerable<string> but is not a List<string>. Arrays are of fixed length. Why do you need it in one line?
Change the type of obj2.Stuff to something like StringCollection or List . In .NET arrays are of fixed length and you can't add new objects to them, so use collections instead.
An IEnumerable does not give you the same features that an IList. Unless your Stuff is an IEnumerable that is also an IList your code won't work.
The contract of the first only promises that you can iterate it one element at a time. It never states that you can add new elements.
You can only pull this off if and only if at runtime your enumerable object also satisfies the IList interface.
As obj2.Stuff is a string array, it's not possible to do what you are trying to do. An array can't be resized, so you can't add items to it.
If you can replace the array in obj2.Stuff with another array, you can get the data from the array and make a list from it, add items to the list, get the data from the list and create an array from it, and use that to replace the original array:
List<string> items = new List<string>(obj2.Stuff);
for (int i = 0; i < 5000; i++) {
items.Add("Iteration " + i.ToString());
}
obj2.Stuff = items.ToArray();
If the obj2.Stuff property is read-only, then you can't add anything to it unless you change then underlying implementation from an array to a collection that you can add items to.

Axapta method return List<Array> , how to convert it in c#

I have in axapta method that return List<Array>. How can I convert it on c# side and for what ? It it possible to convert it to c# List<ArrayList> ? I see example for container:
ArrayList magazynierzy = new ArrayList();
for (int i = 1; i <= axContainer.Count; i++)
{
magazynierzy.Add(axContainer.get_Item(1).ToString());
}
I think there are some significant flaws with this question, but taking it that you have some external process return in list of things, they are easily turned into a list of objects. You should define or identify a class that matches the items you have returned, and create a list of these. So something like:
List<string> magazynierzy = new List<string>();
while(axContainer.ReadNext())
magazynierzy.Add(axContainer.get_Item(1).ToString());
return magazynierzy;
would give you what you need ( I don't know axapta, so I have no idea how you move through the list ). If you need more complex objects, declare a class of struct for them, with a constructor that will take an axContainer object, or a list of parameters which you can pass various get_Item(n) entries into.

How to remove elements from an array

Hi I'm working on some legacy code that goes something along the lines of
for(int i = results.Count-1; i >= 0; i--)
{
if(someCondition)
{
results.Remove(results[i]);
}
}
To me it seems like bad practice to be removing the elements while still iterating through the loop because you'll be modifying the indexes.
Is this a correct assumption?
Is there a better way of doing this? I would like to use LINQ but I'm in 2.0 Framework
The removal is actually ok since you are going downwards to zero, only the indexes that you already passed will be modified. This code actually would break for another reason: It starts with results.Count, but should start at results.Count -1 since array indexes start at 0.
for(int i = results.Count-1; i >= 0; i--)
{
if(someCondition)
{
results.RemoveAt(i);
}
}
Edit:
As was pointed out - you actually must be dealing with a List of some sort in your pseudo-code. In this case they are conceptually the same (since Lists use an Array internally) but if you use an array you have a Length property (instead of a Count property) and you can not add or remove items.
Using a list the solution above is certainly concise but might not be easy to understand for someone that has to maintain the code (i.e. especially iterating through the list backwards) - an alternative solution could be to first identify the items to remove, then in a second pass removing those items.
Just substitute MyType with the actual type you are dealing with:
List<MyType> removeItems = new List<MyType>();
foreach(MyType item in results)
{
if(someCondition)
{
removeItems.Add(item);
}
}
foreach (MyType item in removeItems)
results.Remove(item);
It doesn't seem like the Remove should work at all. The IList implementation should fail if we're dealing with a fixed-size array, see here.
That being said, if you're dealing with a resizable list (e.g. List<T>), why call Remove instead of RemoveAt? Since you're already navigating the indices in reverse, you don't need to "re-find" the item.
May I suggest a somewhat more functional alternative to your current code:
Instead of modifying the existing array one item at a time, you could derive a new one from it and then replace the whole array as an "atomic" operation once you're done:
The easy way (no LINQ, but very similar):
Predicate<T> filter = delegate(T item) { return !someCondition; };
results = Array.FindAll(results, filter);
// with LINQ, you'd have written: results = results.Where(filter);
where T is the type of the items in your results array.
A somewhat more explicit alternative:
var newResults = new List<T>();
foreach (T item in results)
{
if (!someCondition)
{
newResults.Add(item);
}
}
results = newResults.ToArray();
Usually you wouldn't remove elements as such, you would create a new array from the old without the unwanted elements.
If you do go the route of removing elements from an array/list your loop should count down rather than up. (as yours does)
a couple of options:
List<int> indexesToRemove = new List<int>();
for(int i = results.Count; i >= 0; i--)
{
if(someCondition)
{
//results.Remove(results[i]);
indexesToRemove.Add(i);
}
}
foreach(int i in indexesToRemove) {
results.Remove(results[i]);
}
or alternatively, you could make a copy of the existing list, and instead remove from the original list.
//temp is a copy of results
for(int i = temp.Count-1; i >= 0; i--)
{
if(someCondition)
{
results.Remove(results[i]);
}
}

Categories