Something working on most systems but not everywhere c# - c#

I have a console application in C# for Windows and RPi (Mono). I make a filelist and store it in an array. Then there are two files which I don't want in that list, so I want to remove those from the list. This works on most systems where the application runs (Windows and RPi's alike) but there is one RPi - so far - where it refuses to delete one of those files from the list. As if it cannot find the file (because I don't get the message within the if-statement). I am looking for possible causes. Any suggestions?
MonthfileList = Directory.GetFiles("data/", "*log.txt");
for (int i=0; i<MonthfileList.Length; i++)
{
if (MonthfileList[i].Contains("alltimelog") )
{
Sup.LogDebugMessage(message: $"MonthfileList removing: {MonthfileList[i]}");
var foos = new List<string>(MonthfileList);
foos.RemoveAt(i);
MonthfileList = foos.ToArray();
}
}

The stated problem could happen if you have two files with the required string stored in your array MonthFileList in two adiacent indexes.
In this case, the logic inside the loop causes the second file to be evaluated.
Suppose you have an array of 5 elements (index 0-4) where at index 2 and 3 there is a file with the searched word.
When the first index is evaluated (2) the file is removed from the list, then you rebuild the array without the removed file, but this has a secondary effect. The file that was at index 3 is now at index 2 and your indexer that was at 2 is incremented to 3, thus the old element, now at index 2, is not evaluated and remains into the array.
Fix is simple. loop backwards
// Invert logic, so you don't need a conversion list/array each time you find a match
var foos = new List<string>(MonthfileList);
for (int i=foos.Count - 1; i >= 0; i--)
{
if (foos[i].Contains("alltimelog") )
{
Sup.LogDebugMessage(message: $"MonthfileList removing: {foos[i]}");
foos.RemoveAt(i);
}
}
MonthfileList = foos.ToArray();

#Steve made the correct hint. I changed the code with i-- to account for the missing entry:
MonthfileList = Directory.GetFiles("data/", "*log.txt");
for (int i=0; i<MonthfileList.Length; i++)
{
if (MonthfileList[i].Contains("alltimelog") )
{
Sup.LogDebugMessage(message: $"MonthfileList removing: {MonthfileList[i]}");
var foos = new List<string>(MonthfileList);
foos.RemoveAt(i--);
MonthfileList = foos.ToArray();
}
}

Related

C# Using ArrayList.IndexOf with multiple identical items

I've got a situation where I'm using an ArrayList to store a list of file names (full file path). When I add multiple items of the same file to the array, then use ArrayList.IndexOf to find the index (I'm reporting progress to a BackgroundWorker), it always returns the index of the first item since it's searching by the file name. This causes a problem with a progress bar, i.e. I'm processing 3 files, and when complete, the bar is only 1/3 full.
Here's some sample code (I'm simply adding items here, but in the real code they are added from a ListBox):
ArrayList list = new ArrayList();
list.Add("C:\Test\TestFile1.txt");
list.Add("C:\Test\TestFile1.txt");
list.Add("C:\Test\TestFile1.txt");
var files = list;
foreach (string file in files)
backgroundWorker1.ReportProgress(files.IndexOf(file) + 1);
When this runs, only 1 "percent" of progress is reported, since the IndexOf is finding the same file every time. Is there any way around this? Or does anyone have a suggestion on another way to get the index (or any unique identifier for each item)?
The simplest approach is just to use the index to iterate:
for (int i = 0; i < list.Count; i++)
{
backgroundWorks.ReportProgress(i + 1);
// Do stuff with list[i]
}
To achieve what you want, I would recomment using a for list. You won't have to search for any indexes and can report the progress easily to the backgroundWorker1:
for (int counter = 0; counter < files.Count; counter++)
{
backgroundWorker1.ReportProgress(counter + 1);
}
By doing this, you don't get problems with same filenames.
This would be the equivalent with foreach:
int counter = 1;
foreach (string file in files)
{
backgroundWorker1.ReportProgress(counter);
counter++;
}
But I think it's better to use for in this case.
You could make a copy of your list, and then remove each item from it as it is processed. Then you could return the percentage complete as a function of the count of the temp list divided by the count of the original list.
You could also just add to an int every time your background workers process a file and use that int to track the progress (percent complete should be the int divided by the number of files).
Of course with either approach you need to make sure you are modifying the variables in question in a thread-safe manner.
Try this and it works fine for me in case of reading files having so many lines of data.
int percentage = (int)((count / (double)lineCount) * 100.0);
backgroundWorker5.ReportProgress(percentage);
Here count is total count and linecount is present running count. By using thedse two,calculate the percentage. Keep this code in your for loop or while loop.
Assuming that progressbar max value is 100, and with one file processed out of three it should show 33(%) progress, you could count progress for each file processed and recalculate overall progress :
// list contains x file paths
var files = list;
double progressStep = 1 / files.Count;
for(int i = 0; i < files.Count; i++)
{
backgroundWorker1.ReportProgress((i + 1) * progressStep);
...
}
All that remained is to assign progress value in background worker to progress bar.

C# Array of List Index out of bounds

I've made a program that extracts some info from a file , do some operations with it and store it back on a list.
Following this link:
Are 2 dimensional Lists possible in c#?
I've been able to create a class with a list who would suit my needs. But after some debugging i've found that i was overwriting the list on each loop iteration.
Then i decided to make an array of lists - followed this link:
How to create an array of List<int> in C#?
Created an array of lists, initialized it and added elements. But when it needs to move to the next list position , it throws the out of boundaries exception.
I've tried a few things (readed about race condition) but none of 'em worked.
The problem will happen only when i open more than one file with my code ; otherwise it works perfectly.
Exception is thrown at xmldata , in the last iteration of the current file.
Ex: Selected two files, each one will add five elements. In the last element of the first file the exception will be thrown and there's data in the last element's position to be added.
Additional information: Index was outside the bounds of the array. (Exception thrown).
Any help will be appreciated. Thanks a lot.
Code:
List<xmldata>[] finalcontent = new List<xmldata>[9999];
finalcontent[listpos] = new List<xmldata>();//Initializing a list for each filename
foreach (Match m in matches)
{
Double[] numbers;
string aux;
aux = m.Groups[1].ToString();
aux = Regex.Replace(aux, #"\s+", "|");
string[] numbers_str = aux.Split(new[] { "|" }, StringSplitOptions.RemoveEmptyEntries);
numbers = new Double[numbers_str.Length];
for (int j = 0; j < numbers.Length; j++)
{
numbers[j] = Double.Parse(numbers_str[j], CultureInfo.InvariantCulture);
//Converts each number on the string to a Double number, store it in a position
//in the Double array
numbers[j] = numbers[j] / 100; //Needed calculus
numbers[j] = Math.Round(numbers[j], 3); //Storing numbers rounded
}
string values = String.Join(" ", numbers.Select(f => f.ToString()));
if (i <= colors_str.Length)
{
finalcontent[listpos].Add(new xmldata//The exception is thrown right here
{
colorname = colors_str[i],
colorvalues = values,
});//Closing list add declaration
}//Closing if
i++;
}//Closing foreach loop
Link to the file: https://drive.google.com/file/d/0BwU9_GrFRYrTT0ZTS2dRMUhIWms/view?usp=sharing
Arrays are fixed size, but Lists automatically resize as new items are added.
So instead, and since you're using Lists anyway, why not use a list of lists?
List<List<int>> ListOfListsOfInt = new List<List<int>>();
Then, if you really absolutely must have an array, then you can get one like this:
ListOfListsOfString.ToArray();
// Convert non-ascii characters to .
for (int jx = 0; jx < cnt; ++jx)
if (line[jx] < 0x20 || line[jx] > 0x7f) line[jx] = (byte)'.';
This is a big example, but check this one. You increase 'jx' before entering the statement, possibly exceeding the boundary of cnt?
Try changing the following:
if (i <= colors_str.Length)
to
if (i < colors_str.Length).
In fact I'm convinced that this is the problem.
This is because refereces begin at 0 and the last reference is length - 1, not length.
When using a list - it is better to use native functions for it.
List<xmldata>[] finalcontent = new List<xmldata>();
......
finalcontent[listpos] = new List<xmldata>(); insted of var _tmpVariable = new List<xmldata>();//Initializing a list for each filename
......
_tmpVariable.Add(new xmldata
{
colorname = colors_str[i],
colorvalues = values,
});//Closing list add declaration
fs.Close();//closing current file
listpos++;//Increment list position counter
finalcontent.Add(_tmpVariable); // add list into list
As there is no exception details it is hard to get where the exception is thrown.
It could be a list issue, a string issue or other (even file reading issue as well),
So please update this with current exception details.

Looping and changing a list - remove doesn't always work

I'm trying to go through a loop 40 times and changing a list in the process.
This is the code:
for (int i = 0; i < 40; i++)
{
location = rand.Next(rows.Count);
rank = rand2.Next(pondRanks.Count);
ComputerPonds[rows[location]].Rank = (PondRank)pondRanks[rank];
rows.Remove(location);
pondRanks.Remove(rank);
}
For some reason the remove doesn't happen all the time, and only sometimes. Anyone has a suggestion?
Both of the list are List , they have 40 elements, and I want to remove the element itself.
Even when debugging I can see that the list count isn't the same (they both have the same initial numbers and they both need to do remove at this loop). If it matters, I'm working on windows phone platform..
I'm pretty sure you should be using List.RemoveAt not List.Remove. RemoveAt will remove the item at the specified index, whereas Remove will look for that object you passed in and remove it from the List if it's in there. But I'm pretty sure that looking at your code that location and rank represent the index, not the objects themselves.
for (int i = 0; i < 39; i++)
{
location = rand.Next(rows.Count);
rank = rand2.Next(pondRanks.Count);
ComputerPonds[location].Rank = (PondRank)pondRanks[rank];
rows.RemoveAt(location);
pondRanks.RemoveAt(rank);
}
EDIT: You may also want to consider making sure that your rows and pondRanks have enough elements (39) before starting the loop (or altering the i < 39 to max out at the upper limit of their length)

Iterating over an array using index and assigning values depending on index

I was facing this problem earlier today, and since I could not find a satisfactory solution, I decided to change my class design, and have seperate properties such as Tag 1, Tag 2, Tag 3 etc.
My main problem is the fact that I need to bind a grid to an object that contains a list among other properties and I need to show each item in the list as a separate column which I am unable to do. Hence I am resorting to declaring variables separately. Original question is here...
Now, I'm facing one of the most common design problem that probably every programmer has at some point of time. Here is the code to demonstrate it,
for (int i = 0; i < tags.Length; ++i) // Length not known here.
{
if(i==0){
tag1 = tags[0];
}
else if(i == 1){
tag2 = tags[1];
}
else if(i == 2){
tag3 = tags[2];
}
....
}
Here tags is a string array.
I was wondering if there is a more elegant way to do this. Another thing to note is that the efficiency of this loop decreases as it progresses, since with more iterations it has to check more conditions. If we could remove a condition after it had become true once it would speed up each iteration since we know that each condition will become true only once in all the iterations
Moved answer about DataGridView and using ComponentModel to the correct question:
Displaying a list of object containing a list in a grid view
Briefing
The DataGridView controll supports the ComponentModel namespace so that you can create classes that appear to have properties that don't exist. It is the same mechanism the PropertyGrid uses.
The sample code is in this answer of that question:
https://stackoverflow.com/a/13078735/195417
OLD ANSWER
This was my previous answer, when I didn't realize the real question was about the DataGridView control.
Isn't this the same as setting the values directly:
this.tag1 = tags[0];
this.tag2 = tags[1];
this.tag3 = tags[2];
EDIT: as you sayd you don't know how many variables will be needed, then you need only one, and that is a list:
var list = new List<string>();
for (int i = 0; i < tags.Length; ++i)
{
list.add(tags[i]);
}
If all you want is to copy all values, you can even do this:
var list = new List<string>(tags);
Tell me whether this is what you want or not... maybe I have misunderstood the question.
The whole loop is pointless. But unless the tags array length is always going to be the same, you have to be sure not to go out of bounds...
if(tags.Length >= 1) this.tag1 = tags[0];
if(tags.Length >= 2) this.tag2 = tags[1];
if(tags.Length >= 3) this.tag3 = tags[2];
if(tags.Length >= 4) this.tag4 = tags[3];
if(tags.Length >= 5) this.tag5 = tags[4];
... so on for however many this.tag# you have.
This is essentially the same:
for(int index = 0; index < tags.Length[]; index++){
switch(index){
case 0:
tag1 = tags[0];
break;
// And so on
}
}

Create text files of every combination of specific lines within a base text file

Ok, so hopefully I can explain this in enough detail for somebody to be able to help me.. I am writing a program in C# that is supposed to take a text file and replace specific text, which happen to be names of files, and print a new text file for every single combination of the given filenames. The specific places to change the text of filenames have their own set of possible filenames, listed as an array described below. The program should run regardless of how many filenames are available for each location as well as how many total locations for the filenames. If you really wanted to make it awesome, it can be slightly optimized knowing that no filenames should be duplicated throughout any single text file.
text is an array of lines that make up the base of the total file.
lineNum holds an array of the line locations of the filename entries.
previousFiles is an array of previously used filenames, starting with what is already in the file.
files is a jagged 2-dimensional array of possible filenames where files[1] would be an array of all the possible filenames for the 2nd location
Here is an example of how it would work with 3 separate filename locations, the first one given 3 possible filenames, the second given 8 possible filenames, and the third given 3 possible filenames.
Oh and assume buildNewFile works.
int iterator = 0;
for (int a = 0; a < 3; a++)
{
for (int b = 0; b < 8; b++)
{
for (int c = 0; c < 3; c++)
{
iterator++;
text[lineNums[0]] = text[lineNums[0]].Replace(previousFiles[0], files[0][a]);
text[lineNums[1]] = text[lineNums[1]].Replace(previousFiles[0], files[0][a]);
text[lineNums[2]] = text[lineNums[2]].Replace(previousFiles[1], files[1][b]);
text[lineNums[3]] = text[lineNums[3]].Replace(previousFiles[1], files[1][b]);
text[lineNums[4]] = text[lineNums[4]].Replace(previousFiles[2], files[2][c]);
text[lineNums[5]] = text[lineNums[5]].Replace(previousFiles[2], files[2][c]);
previousFiles = new string[] { files[0][a], files[1][b], files[2][c] };
buildNewFile(text, Info.baseFolder + "networks\\" + Info.dsnFilename + iterator + ".dsn");
}
}
}
If you guys can help me, thank you so much, I just can't figure out how to do it recursively or anything. If you have any questions I'll answer them and edit up here to reflect that.
It took me a little while to figure out what you really wanted to do. This problem can be solved without recursion, the trick is to look at the data you have and get it into a more usable format.
Your "files" array is the one that is the most inconvenient. The trick is to transform the data into usable permutations. To do that, I suggest taking advantage of yield and using a method that returns IEnumerable. The code for it is here:
public IEnumerable<string[]> GenerateFileNameStream(string[][] files)
{
int[] current_indices = new int[files.Length];
current_indices.Initialize();
List<string> file_names = new List<string>();
while (current_indices[0] < files[0].Length)
{
file_names.Clear();
for (var index_index = 0; index_index < current_indices.Length; index_index++)
{
file_names.Add(files[index_index][current_indices[index_index]]);
}
yield return file_names.ToArray();
// increment the indices, trickle down as needed
for (var check_index = 0; check_index < current_indices.Length; check_index++)
{
current_indices[check_index]++;
// if the index hasn't rolled over, we're done here
if (current_indices[check_index] < files[check_index].Length) break;
// if the last location rolls over, then we are totally done
if (check_index == current_indices.Length - 1) yield break;
// reset this index, increment the next one in the next iteration
current_indices[check_index] = 0;
}
}
}
Basically, it keeps track of the current index for each row of the files 2D array and returns the file name at each current index. Then it increments the first index. If the first index rolls over, then it resets to 0 and increments the next index instead. This way we can iterate through every permutation of the file names.
Now, looking at the relationship between lineNum and files, I assume that each location in the file is copied to two lines. The rest of the code is here:
public void MakeItWork(string[][] files, int[] lineNum, string[] text, string[] previousFiles)
{
var iterator = 0;
var filenames = GenerateFileNameStream(files);
// work a copy of the text, assume the "previousFiles" are in this text
var text_copy = new string[text.Length];
foreach (var filenameset in filenames)
{
iterator++;
Array.Copy(text, text_copy, text.Length);
for (var line_index = 0; line_index < lineNum.Length; line_index++)
{
var line_number = lineNum[line_index];
text[line_number] = text[line_number].Replace(previousFiles[line_index], filenameset[line_index / 2]);
}
buildNewFile(text_copy, Info.baseFolder + "networks\\" + Info.dsnFilename + iterator + ".dsn");
}
}
This code just takes the results from the enumerator and generates the files for you. The assumption based on your sample code is that each filename location is used twice per file (since the lineNum array was twice as long as the files location count.
I haven't fully tested all the code, but the crux of the algorithm is there. The key is to transform your data into a more usable form, then process it. The other suggestion I have when asking a question here is to describe the problem more as a "problem" and not in the terms of your current solution. If you detailed the goal you are trying to achieve instead of showing code, you can get more insights into the problem.

Categories