I am trying to make a 1d array of lists. I make it like this:
public static List<string>[] words = new List<string>[30];
public static List<string>[] hints = new List<string>[30];
And I call it like this:
foreach (string item in vars.directory)
{
reader2 = new StreamReader(item);
while (reader2.Peek() > 0)
{
string line = reader2.ReadLine();
if (line.StartsWith("#"))
{
vars.words[counter].Add(line.Substring(1, line.Length - 1)); //here
}
else if (line.StartsWith("-"))
{
vars.hints[counter].Add(line.Substring(1, line.Length - 1)); //another here
}
else if (line == "#end")
{
counter++;
}
}
}
I just wanted to add that vars is where I keep my public variables and that counter is indeed at 0 when the loop starts.
EDIT
In my haste I forgot to add the question... oops...
Here it is: When I call the add function (or any another function for that matter) it returns a null reference exception. How can I fix this?
I assume you're crashing when attempting to call .Add on your array element. You need to initialize your arrays with valid objects.
for( Int32 i = 0; i < vars.words.Length; ++i )
vars.words[i] = new List<string>();
for( Int32 i = 0; i < vars.hints.Length; ++i )
vars.hints[i] = new List<string>();
Why not just make a List<List<string>>, but yes you can make an array of lists
Using a list of lists, as already recommended, would make you escape your problems,
and it´s much more flexible and handy than your construction.
-> f.i. if the size of your data changes, you don´t have to change the list size, but the array
Here's a one-liner to initialize an array of lists of size 30:
static List<string>[] lists = (from i in Enumerable.Range(0, 30)
select new List<string>()).ToArray();
The problem is that array values are initialized to the default value, and the default value for reference types is null.
default(List<string>) returns null.
So, you'll need to re-initialize the objects in the array before you can access them, otherwise you will get a NullReferenceException.
One way to initialize all the objects in your array up front is to use this Linq statement:
const int sizeOfLists = 5;
List<string>[] lists = Enumerable.Range(0, sizeOfLists)
.Select(i => new List<string>())
.ToArray();
Another option is to initialize and add the sub-lists only when you need them, by using an outer List:
var lists = new List<List<string>>();
// ...
var aSubList = new List<string>();
lists.Add(aSubList);
This is particularly useful if you don't know the size of the outer set of lists up-front, and is still accessible by index.
(This was a comment before, but I made it an answer since many other answers got caught up in the solution and don't describe the problem)
You could initialize the lists right before you use them:
foreach (string item in vars.directory)
{
reader2 = new StreamReader(item);
while (reader2.Peek() > 0)
{
string line = reader2.ReadLine();
// new code
if (vars.words[counter] == null) vars.words[counter] = new List<string>();
if (vars.hints[counter] == null) vars.hints[counter] = new List<string>();
if (line.StartsWith("#"))
{
vars.words[counter].Add(line.Substring(1, line.Length - 1)); //here
}
else if (line.StartsWith("-"))
{
vars.hints[counter].Add(line.Substring(1, line.Length - 1)); //another here
}
else if (line == "#end")
{
counter++;
}
}
}
Related
Assume we have an array list of type Employe , does expanding it's length by 1 make a new object in the list ?
is the code in else statement correct? and is it recommended?
public void ModifierEmp(int c)
{
for(int i = 0; i < Ann.Count; i++)
{
if(Ann[i].Code == c)
{
Ann[i].saisie();
} else
{
i = Ann.Count + 1; //expanding arraylist ann
Ann[i].saisie(); //saisie a method for the user to input Employe infos
}
}
}
https://imgur.com/VfFHDKu "code snippet"
i = Ann.Count + 1;
The code above is not expanding the list: it is only setting your index variable (i) to have a new value.
If you wanted to make the list bigger, you would have to tell it which object to put into that new space you create. For example:
Ann.Add(anotherItem);
Of course, this gives you the ability to decide whether to add an existing item, create a new item (e.g. Ann.Add(new Something() { Code = c })), or even add a null value to the list (which is not usually a good idea).
I've been trying to figure out how to remove elements in my ArrayList where the value contains some text string.
My Array could look like this:
[0] "\"MAERSKA.CO\",N/A,N/A,N/A,N/A,N/A,N/A"
[1] "\"GEN.COABB.ST\",N/A,N/A,N/A,N/A,N/A,N/A"
[2] "\"ARCM.ST\",\"Arcam AB\",330.00,330.50,332.00,330.50,330.00"
And my ArrayList is created like this:
string stringToRemove = "NA";
ArrayList rows = new ArrayList(csvData.Replace("\r", "").Split('\n'));
So the question is how I delete all entries that contains "NA".
I have tried the RemoveAt or RemoveAll with several combinations of Contains but i cant seem to get the code right.
I do not want to make a new Array if it can be avoided.
Regards
Flemming
If you want to reduce your ArrayList before instantiate your variable, consider using LINQ:
ArrayList rows = new ArrayList(csvData.Replace("\r", "").Split('\n').Where(r => !r.Contains(stringToRemove)).ToList());
If you want to reduce your ArrayList after instantiation, you can try this:
for (int i = 0; i < rows.Count; i++)
{
var row = (string)rows[i];
if (row.Contains(stringToRemove))
{
rows.RemoveAt(i);
i--;
}
}
The following code creates a list as output containing all strings except "N/A":
var outputs = new List<string>();
foreach (var item in input)
{
var splitted = item.Split(',');
foreach (var splt in splitted)
{
if (splt != "N/A")
{
outputs.Add(splt);
}
}
}
The input is your array.
A new feature in C# / .NET 4.0 is that you can change your enumerable in a foreach without getting the exception. See Paul Jackson's blog entry An Interesting Side-Effect of Concurrency: Removing Items from a Collection While Enumerating for information on this change.
What is the best way to do the following?
foreach(var item in Enumerable)
{
foreach(var item2 in item.Enumerable)
{
item.Add(new item2)
}
}
Usually I use an IList as a cache/buffer until the end of the foreach, but is there better way?
The collection used in foreach is immutable. This is very much by design.
As it says on MSDN:
The foreach statement is used to
iterate through the collection to get
the information that you want, but can
not be used to add or remove items
from the source collection to avoid
unpredictable side effects. If you
need to add or remove items from the
source collection, use a for loop.
The post in the link provided by Poko indicates that this is allowed in the new concurrent collections.
Make a copy of the enumeration, using an IEnumerable extension method in this case, and enumerate over it. This would add a copy of every element in every inner enumerable to that enumeration.
foreach(var item in Enumerable)
{
foreach(var item2 in item.Enumerable.ToList())
{
item.Add(item2)
}
}
To illustrate Nippysaurus's answer: If you are going to add the new items to the list and want to process the newly added items too during the same enumeration then you can just use for loop instead of foreach loop, problem solved :)
var list = new List<YourData>();
... populate the list ...
//foreach (var entryToProcess in list)
for (int i = 0; i < list.Count; i++)
{
var entryToProcess = list[i];
var resultOfProcessing = DoStuffToEntry(entryToProcess);
if (... condition ...)
list.Add(new YourData(...));
}
For runnable example:
void Main()
{
var list = new List<int>();
for (int i = 0; i < 10; i++)
list.Add(i);
//foreach (var entry in list)
for (int i = 0; i < list.Count; i++)
{
var entry = list[i];
if (entry % 2 == 0)
list.Add(entry + 1);
Console.Write(entry + ", ");
}
Console.Write(list);
}
Output of last example:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 3, 5, 7, 9,
List (15 items)
0
1
2
3
4
5
6
7
8
9
1
3
5
7
9
As mentioned, but with a code sample:
foreach(var item in collection.ToArray())
collection.Add(new Item...);
You should really use for() instead of foreach() in this case.
You can't change the enumerable collection while it is being enumerated, so you will have to make your changes before or after enumerating.
The for loop is a nice alternative, but if your IEnumerable collection does not implement ICollection, it is not possible.
Either:
1) Copy collection first. Enumerate the copied collection and change the original collection during the enumeration. (#tvanfosson)
or
2) Keep a list of changes and commit them after the enumeration.
LINQ is very effective for juggling with collections.
Your types and structure are unclear to me, but I will try to fit your example to the best of my ability.
From your code it appears that, for each item, you are adding to that item everything from its own 'Enumerable' property. This is very simple:
foreach (var item in Enumerable)
{
item = item.AddRange(item.Enumerable));
}
As a more general example, let's say we want to iterate a collection and remove items where a certain condition is true. Avoiding foreach, using LINQ:
myCollection = myCollection.Where(item => item.ShouldBeKept);
Add an item based on each existing item? No problem:
myCollection = myCollection.Concat(myCollection.Select(item => new Item(item.SomeProp)));
Here's how you can do that (quick and dirty solution. If you really need this kind of behavior, you should either reconsider your design or override all IList<T> members and aggregate the source list):
using System;
using System.Collections.Generic;
namespace ConsoleApplication3
{
public class ModifiableList<T> : List<T>
{
private readonly IList<T> pendingAdditions = new List<T>();
private int activeEnumerators = 0;
public ModifiableList(IEnumerable<T> collection) : base(collection)
{
}
public ModifiableList()
{
}
public new void Add(T t)
{
if(activeEnumerators == 0)
base.Add(t);
else
pendingAdditions.Add(t);
}
public new IEnumerator<T> GetEnumerator()
{
++activeEnumerators;
foreach(T t in ((IList<T>)this))
yield return t;
--activeEnumerators;
AddRange(pendingAdditions);
pendingAdditions.Clear();
}
}
class Program
{
static void Main(string[] args)
{
ModifiableList<int> ints = new ModifiableList<int>(new int[] { 2, 4, 6, 8 });
foreach(int i in ints)
ints.Add(i * 2);
foreach(int i in ints)
Console.WriteLine(i * 2);
}
}
}
To add to Timo's answer LINQ can be used like this as well:
items = items.Select(i => {
...
//perform some logic adding / updating.
return i / return new Item();
...
//To remove an item simply have logic to return null.
//Then attach the Where to filter out nulls
return null;
...
}).Where(i => i != null);
The best approach from a performance perspective is probably to use a one or two arrays. Copy the list to an array, do operations on the array, and then build a new list from the array. Accessing an array element is faster than accessing a list item, and conversions between a List<T> and a T[] can use a fast "bulk copy" operation which avoids the overhead associated accessing individual items.
For example, suppose you have a List<string> and wish to have every string in the list which starts with T be followed by an item "Boo", while every string that starts with "U" is dropped entirely. An optimal approach would probably be something like:
int srcPtr,destPtr;
string[] arr;
srcPtr = theList.Count;
arr = new string[srcPtr*2];
theList.CopyTo(arr, theList.Count); // Copy into second half of the array
destPtr = 0;
for (; srcPtr < arr.Length; srcPtr++)
{
string st = arr[srcPtr];
char ch = (st ?? "!")[0]; // Get first character of string, or "!" if empty
if (ch != 'U')
arr[destPtr++] = st;
if (ch == 'T')
arr[destPtr++] = "Boo";
}
if (destPtr > arr.Length/2) // More than half of dest. array is used
{
theList = new List<String>(arr); // Adds extra elements
if (destPtr != arr.Length)
theList.RemoveRange(destPtr, arr.Length-destPtr); // Chop to proper length
}
else
{
Array.Resize(ref arr, destPtr);
theList = new List<String>(arr); // Adds extra elements
}
It would have been helpful if List<T> provided a method to construct a list from a portion of an array, but I'm unaware of any efficient method for doing so. Still, operations on arrays are pretty fast. Of note is the fact that adding and removing items from the list does not require "pushing" around other items; each item gets written directly to its appropriate spot in the array.
I have written one easy step, but because of this performance will be degraded
Here is my code snippet:-
for (int tempReg = 0; tempReg < reg.Matches(lines).Count; tempReg++)
{
foreach (Match match in reg.Matches(lines))
{
var aStringBuilder = new StringBuilder(lines);
aStringBuilder.Insert(startIndex, match.ToString().Replace(",", " ");
lines[k] = aStringBuilder.ToString();
tempReg = 0;
break;
}
}
A new feature in C# / .NET 4.0 is that you can change your enumerable in a foreach without getting the exception. See Paul Jackson's blog entry An Interesting Side-Effect of Concurrency: Removing Items from a Collection While Enumerating for information on this change.
What is the best way to do the following?
foreach(var item in Enumerable)
{
foreach(var item2 in item.Enumerable)
{
item.Add(new item2)
}
}
Usually I use an IList as a cache/buffer until the end of the foreach, but is there better way?
The collection used in foreach is immutable. This is very much by design.
As it says on MSDN:
The foreach statement is used to
iterate through the collection to get
the information that you want, but can
not be used to add or remove items
from the source collection to avoid
unpredictable side effects. If you
need to add or remove items from the
source collection, use a for loop.
The post in the link provided by Poko indicates that this is allowed in the new concurrent collections.
Make a copy of the enumeration, using an IEnumerable extension method in this case, and enumerate over it. This would add a copy of every element in every inner enumerable to that enumeration.
foreach(var item in Enumerable)
{
foreach(var item2 in item.Enumerable.ToList())
{
item.Add(item2)
}
}
To illustrate Nippysaurus's answer: If you are going to add the new items to the list and want to process the newly added items too during the same enumeration then you can just use for loop instead of foreach loop, problem solved :)
var list = new List<YourData>();
... populate the list ...
//foreach (var entryToProcess in list)
for (int i = 0; i < list.Count; i++)
{
var entryToProcess = list[i];
var resultOfProcessing = DoStuffToEntry(entryToProcess);
if (... condition ...)
list.Add(new YourData(...));
}
For runnable example:
void Main()
{
var list = new List<int>();
for (int i = 0; i < 10; i++)
list.Add(i);
//foreach (var entry in list)
for (int i = 0; i < list.Count; i++)
{
var entry = list[i];
if (entry % 2 == 0)
list.Add(entry + 1);
Console.Write(entry + ", ");
}
Console.Write(list);
}
Output of last example:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 3, 5, 7, 9,
List (15 items)
0
1
2
3
4
5
6
7
8
9
1
3
5
7
9
As mentioned, but with a code sample:
foreach(var item in collection.ToArray())
collection.Add(new Item...);
You should really use for() instead of foreach() in this case.
You can't change the enumerable collection while it is being enumerated, so you will have to make your changes before or after enumerating.
The for loop is a nice alternative, but if your IEnumerable collection does not implement ICollection, it is not possible.
Either:
1) Copy collection first. Enumerate the copied collection and change the original collection during the enumeration. (#tvanfosson)
or
2) Keep a list of changes and commit them after the enumeration.
LINQ is very effective for juggling with collections.
Your types and structure are unclear to me, but I will try to fit your example to the best of my ability.
From your code it appears that, for each item, you are adding to that item everything from its own 'Enumerable' property. This is very simple:
foreach (var item in Enumerable)
{
item = item.AddRange(item.Enumerable));
}
As a more general example, let's say we want to iterate a collection and remove items where a certain condition is true. Avoiding foreach, using LINQ:
myCollection = myCollection.Where(item => item.ShouldBeKept);
Add an item based on each existing item? No problem:
myCollection = myCollection.Concat(myCollection.Select(item => new Item(item.SomeProp)));
Here's how you can do that (quick and dirty solution. If you really need this kind of behavior, you should either reconsider your design or override all IList<T> members and aggregate the source list):
using System;
using System.Collections.Generic;
namespace ConsoleApplication3
{
public class ModifiableList<T> : List<T>
{
private readonly IList<T> pendingAdditions = new List<T>();
private int activeEnumerators = 0;
public ModifiableList(IEnumerable<T> collection) : base(collection)
{
}
public ModifiableList()
{
}
public new void Add(T t)
{
if(activeEnumerators == 0)
base.Add(t);
else
pendingAdditions.Add(t);
}
public new IEnumerator<T> GetEnumerator()
{
++activeEnumerators;
foreach(T t in ((IList<T>)this))
yield return t;
--activeEnumerators;
AddRange(pendingAdditions);
pendingAdditions.Clear();
}
}
class Program
{
static void Main(string[] args)
{
ModifiableList<int> ints = new ModifiableList<int>(new int[] { 2, 4, 6, 8 });
foreach(int i in ints)
ints.Add(i * 2);
foreach(int i in ints)
Console.WriteLine(i * 2);
}
}
}
To add to Timo's answer LINQ can be used like this as well:
items = items.Select(i => {
...
//perform some logic adding / updating.
return i / return new Item();
...
//To remove an item simply have logic to return null.
//Then attach the Where to filter out nulls
return null;
...
}).Where(i => i != null);
The best approach from a performance perspective is probably to use a one or two arrays. Copy the list to an array, do operations on the array, and then build a new list from the array. Accessing an array element is faster than accessing a list item, and conversions between a List<T> and a T[] can use a fast "bulk copy" operation which avoids the overhead associated accessing individual items.
For example, suppose you have a List<string> and wish to have every string in the list which starts with T be followed by an item "Boo", while every string that starts with "U" is dropped entirely. An optimal approach would probably be something like:
int srcPtr,destPtr;
string[] arr;
srcPtr = theList.Count;
arr = new string[srcPtr*2];
theList.CopyTo(arr, theList.Count); // Copy into second half of the array
destPtr = 0;
for (; srcPtr < arr.Length; srcPtr++)
{
string st = arr[srcPtr];
char ch = (st ?? "!")[0]; // Get first character of string, or "!" if empty
if (ch != 'U')
arr[destPtr++] = st;
if (ch == 'T')
arr[destPtr++] = "Boo";
}
if (destPtr > arr.Length/2) // More than half of dest. array is used
{
theList = new List<String>(arr); // Adds extra elements
if (destPtr != arr.Length)
theList.RemoveRange(destPtr, arr.Length-destPtr); // Chop to proper length
}
else
{
Array.Resize(ref arr, destPtr);
theList = new List<String>(arr); // Adds extra elements
}
It would have been helpful if List<T> provided a method to construct a list from a portion of an array, but I'm unaware of any efficient method for doing so. Still, operations on arrays are pretty fast. Of note is the fact that adding and removing items from the list does not require "pushing" around other items; each item gets written directly to its appropriate spot in the array.
I have written one easy step, but because of this performance will be degraded
Here is my code snippet:-
for (int tempReg = 0; tempReg < reg.Matches(lines).Count; tempReg++)
{
foreach (Match match in reg.Matches(lines))
{
var aStringBuilder = new StringBuilder(lines);
aStringBuilder.Insert(startIndex, match.ToString().Replace(",", " ");
lines[k] = aStringBuilder.ToString();
tempReg = 0;
break;
}
}
I have some strange problem where all my string arrays has the same value in the List.
Here is my code:
List<string[]> map_data = new List<string[]>();
string[] map_data_array = new string[11];
for(int i = 0; i < 2000; i++)
{
map_data_array = PopulateDataFromFile(); // it returns different data every call
map_data.Add(map_data_array); // store to List
}
map_data_array has always different data, I've verified that by placing the break point there and I've checked it.
The problem is that map_data has the value of all elements the same. And this value is the data that comes from function PopulateDataFromFile when the i is 1999.
What I am doing wrong? :/
That only happens if you place the same array into the list. As you did not give the code to PopulateDataFromFile we can only guess what happens. Make sure that the function returns a seperate array created with new each time.
You need to process your data in chunks since PopulateDataFromFile(); looks to be returning all of its data in one go (or as much as the array can fit). Using an extension method, you could do something like this: -
List<string[]> map_data = new List<string[]>();
foreach (var batch in PopulateDataFromFile().Batch(11))
{
map_data.Add((batch.ToArray());
}
Extension method: -
public static IEnumerable<IEnumerable<T>> Batch<T>(this IEnumerable<T> items, int batchSize)
{
return items.Select((item, inx) => new { item, inx })
.GroupBy(x => x.inx / batchSize)
.Select(g => g.Select(x => x.item));
}
PopulateDataFromFile() is returning a String array with the same values.
In the loop everytime you just change the address of map_data_array , so that's why always the value will get changed to the newer data obtained from the method call. Reinitialize the string array everytime will help. It should look something like this
for(int i = 0; i < 2000; i++)
{
string[] map_data_array = PopulateDataFromFile(); // it returns different data every call
map_data.Add(map_data_array); // store to List
}
or if its confusing for you can you make it simple by
for(int i = 0; i < 2000; i++)
{
map_data.Add(PopulateDataFromFile()); // store to List
}