I am checking if a file exists, and if it does, I put it in a list, otherwise I remove from the list. My code is so:
foreach (KeyValuePair<string, string> kvp in dict)
{
_savedxml.Add(kvp.Key.ToString());
}
string namewithext=null;
for (int i = 0; i < _savedxml.Count; i++)
{
namewithext = string.Concat(_savedxml[i], ".xml");
System.IO.FileInfo file_info = new System.IO.FileInfo((string)namewithext);
long size = file_info.Length;
if (size == 0)
{
_savedxml.RemoveAt(i);
}
}
for (int i = 0; i < _savedxml.Count; i++)
{
if (System.IO.File.Exists(System.IO.Path.GetFullPath(namewithext)))
{
}
else
{
_savedxml.Remove(namewithext);
}
}
I've tried many ways, but even though a file does not exist, the list contains it. I've probably made a silly error.
How can I do this?
There are several errors in the code:
You set the namewithext variable for each item in the first loop, then use it in the second loop, so you will be checking if the last file exist over and over.
When you remove an item, the next item takes its place in the list, so you will skip the check for the next item.
You are checking the length of the files before checking if the files exist, so you will get a FileNotFoundException when you try to get the length for files that doesn't exist.
Corrected (and some cleanup):
foreach (KeyValuePair<string, string> kvp in dict) {
_savedxml.Add(kvp.Key);
}
for (int i = _savedxml.Count - 1; i >= 0 ; i--) {
string namewithext = _savedxml[i] + ".xml";
if (!System.IO.File.Exists(System.IO.Path.GetFullPath(namewithext))) {
_savedxml.RemoveAt(i);
}
}
for (int i = _savedxml.Count - 1; i >= 0 ; i--) {
string namewithext = _savedxml[i] + ".xml";
System.IO.FileInfo file_info = new System.IO.FileInfo(namewithext);
if (file_info.Length == 0) {
_savedxml.RemoveAt(i);
}
}
There are two problems with your code that I can spot:
Getting the Length property of a FileInfo instance that refers to a file that doesn't exist should throw an exception, not return 0.
In the second for-loop you iterate over your savedxml list, yet you never change the "namewithext"-variable, which would cause you to try and remove the same entry every time.
EDIT
Additionally, Duncan is right, of course, if the code inside the "if (size == 0)" branch would ever run, you'd skip an entry in your list.
You're removing an item from your collection by index, which will then change the position of the remaining items in your collection. It will then end up skipping an entry which it should have removed.
_savedxml has file names without extesnion, so before _savedxml.Remove(namewithext); remove extesnion from namewithext.
foreach (KeyValuePair<string, string> kvp in dict)
{
_savedxml.Add(kvp.Key.ToString());
}
string namewithext = null;
int i = 0;
while (i < _savedxml.Count)
{
namewithext = string.Concat(_savedxml[i], ".xml");
System.IO.FileInfo file_info = new System.IO.FileInfo((string)namewithext);
if (!file_info.Exists || file_info.Length == 0)
_savedxml.RemoveAt(i);
else
i++;
}
Related
i have a problem with the code i showed below.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
namespace problem2
{
class Program
{
static void Main(string[] args)
{
int[] nums = Console.ReadLine().Split().Select(int.Parse).ToArray();
List<int> lst = nums.OfType<int>().ToList();
while (true)
{
string des = Console.ReadLine();
var output = Regex.Replace(des.Split(" ")[0], #"[^0-9a-zA-Z\ ]+", "");
if (output == "Add")
{
string val = Regex.Replace(des, "[^0-9]", "");
int value = int.Parse(val);
lst.Add(value);
}
else if(output == "Remove")
{
string val = Regex.Replace(des, "[^0-9]", "");
int value = int.Parse(val);
lst.Remove(value);
}else if(output == "Replace")
{
String result1 = System.Text.RegularExpressions.Regex.Match(des, #"\d+").Value;
var lastno = des.Split().Last();
List<int> lst2 = lst;
for (int i = 0; i < lst2.Count; i++)
{
if(lst[i] == int.Parse(result1))
{
lst[i] = int.Parse(lastno);
break;
}
}
lst = lst2;
}
else if(output == "Collapse")
{
string val = Regex.Replace(des, "[^0-9]", "");
int value = int.Parse(val);
for(int i = 0; i < lst.Count; i+=1)
{
int element = (int)lst[i];
if (element < value)
{
lst.RemoveAt(i);
}
else
{
continue;
}
}
}else if (output == "Mort")
{
PrintValues(lst);
break;
}
}
}
public static void PrintValues(IEnumerable myList)
{
foreach (Object obj in myList)
Console.Write("{0} ", obj);
Console.WriteLine();
}
}
}
more precisely with this part of the code:
else if(output == "Collapse")
{
string val = Regex.Replace(des, "[^0-9]", "");
int value = int.Parse(val);
for(int i = 0; i < lst.Count; i+=1)
{
int element = (int)lst[i];
if (element < value)
{
lst.RemoveAt(i);
}
else
{
continue;
}
}
I tried with all sorts of options but the loop misses elements. as an example
entrance:
1 2 -1 0 -3 9 8 7 2
Collapse 8
Mort
output:
9 8
but the program gives me this output:
2 0 9 8 2
I tried to see what the problem is through the debugger and there I found that the loop misses elements
It should be,
for(int i = 0; i < lst.Count; i+=1)
{
int element = (int)lst[i];
if (element < value)
{
lst.RemoveAt(i);
i--;
}
else
{
continue;
}
}
As #David784 mentioned at the comments. When you remove element the from the itterating collection. You miss 1 element everytime after you delete the i item.
To elaborate on #Berkay's comment: You're changing a list as you're looping through it. If i is 2 and you remove that element, then the element that used to be at index 3 now becomes 2, and so forth. His method of decrementing i will work. Another way would be to use a linq .Where statement instead:
var newList = lst.Where(e=> e>=value).ToList();
You are modifying the collection you are iterating through. This moves elements to other indexes and invalidates the i you determine for following elements in the for header. Better loop backwards
for (int i = lst.Count - 1; i >= 0; i--) {
// Now you can safely remove (or add) elements without affecting
// the index of non yet processed elements.
}
You are still modifying the index of elements ahead, but you are moving backwards, now.
In Visual Studio, you can use the forr code snippet to create a reverse for-loop. Type
forr <tab> <tab>.
(and of course there is the for code snippet for a normal for loop. It will increment the index with i++ instead of i += 1.)
Also, if the list is very long and you are removing many elements, it is worth to think about performance. This approach could move around a great number of elements. Copying the elements you want to keep to a new list (initialized with an appropriate initial capacity), will be more performing in this case.
The code below is supposed to read a text file and count all ASCII characters in the file and add up the frequency. Then, it has to write the character, ASCII value and frequency to an output file. The code is below:
class CharacterFrequency
{
char ch;
int frequency;
public char getCharacter()
{
return ch;
}
public void setCharacter(char ch)
{
this.ch = ch;
}
public int getfrequency()
{
return frequency;
}
public void setfrequency(int frequency)
{
this.frequency = frequency;
}
static void Main()
{
Console.WriteLine("Enter the file path");
var InputFileName = Console.ReadLine();
Console.WriteLine("Enter the outputfile name");
var OutputFileName = Console.ReadLine();
StreamWriter streamWriter = new StreamWriter(OutputFileName);
string data = File.ReadAllText(InputFileName);
ArrayList al = new ArrayList();
//create two for loops to traverse through the arraylist and compare
for (int i = 0; i < data.Length; i++)
{
int k = 0;
int f = 0;
for (int j = 0; j < data.Length; j++)
{
if (data[i].Equals(data[j]))
{
f++;
}
}
if (!al.Contains(data[i]))
{
al.Add(data[i] + "(" + (int)data[i] + ")" + f + " ");
}
else
{
k++;
}
//i added the below if statement but it did not fix the issue
foreach (var item in al)
{
streamWriter.WriteLine(item);
}
}
streamWriter.Close();
}
}
The code compiles and runs perfectly fine, but the output file is not correct. It is adding letters that have already been reviewed. I've added an image with the output file showing the incorrect output it is creating. --> enter image description here
How do I check if a character already exists in the array list? The way I am using is not working properly and I have been working on this for a few weeks now to no success. I have tried using the debugger but this issue will not show up there as the code still runs and compiles correctly.
An ArrayList is not well suited for this task, and in fact ArrayLists are not really used anymore. If someone is telling you that you have to do this with an ArrayList
A dictionary would be a much better container for this data. You can use the character as the key, and the count as the value.
Here's one way to do this:
var inputPath = #"c:\temp\temp.txt";
var outputPath = #"c:\temp\results.txt";
var data = new Dictionary<char, int>();
// For each character in the file, add it to the dictionary
// or increment the count if it already exists
foreach (var character in File.ReadAllText(inputPath))
{
if (data.ContainsKey(character)) data[character]++;
else data.Add(character, 1);
}
// Create our results summary
var results = data.ToList()
.Select(item => $"{item.Key} ({(int) item.Key}) {item.Value}");
// Write results to output file
File.WriteAllLines(outputPath, results);
If you have to use an ArrayList (which no one ever uses anymore, but you say have you to for some reason), it would only be useful for storing the results but not keeping track of the counts.
One way to use an ArrayList would be in combination with the Linq extension methods Distinct and Count (first to find all distinct characters, and next to get the count of each one):
foreach (var chr in data.Distinct())
{
al.Add($"{chr} ({(int) chr}) {data.Count(c => c == chr)}");
}
Your algorithm works, but you are duplicating the output as you are writing to the file inside the loop, that is why you are seeing duplicates in the result. If you move the code outside the loop, it should be ok.
foreach (var item in al)
{
streamWriter.WriteLine(item);
}
I would suggest that your algorithm while correct will behave poorly for performance, you are doing too many unnecessary comparisons, perhaps you should read/check more about using dictionaries to store the results.
I add some files to a listbox on a button:
if (Directory.Exists(DirString))
{
DirectoryInfo dirETC = new DirectoryInfo(DirString);
FileInfo[] Files = dirETC.GetFiles("*.txt");
foreach (FileInfo file in Files)
{
listBox1.Items.Add(file.FullName);
}
If user clicks the delete button, i would like to delete all files in the listbox like this:
try
{
listBox1.BeginUpdate();
for (int i = 0; i < listBox1.Items.Count; i++)
{
string filename = listBox1.Items[i].ToString();
if (File.Exists(filename))
{
File.Delete(filename);
listBox1.Items.Remove(filename);
}
}
listBox1.EndUpdate();
}
catch (Exception)
{
return;
}
The above code works, but its only deleting one file every time i click the delete all button. I think I need to add some kind of foreach loop here to iterate through the items but i'm not sure what is the best way to go about it.
Foreach statement won't allow you to modify a collection you are iterating through, while for will. You just have to be careful with indexes: in your solution after removing the first item (with index=0) the next one become first. Try this approach instead:
listBox1.BeginUpdate();
for (int i = listBox1.Items.Count - 1; i >=0; i--)
{
string filename = listBox1.Items[i].ToString();
if (File.Exists(filename))
{
try
{
File.Delete(filename);
listBox1.Items.Remove(filename);
}
catch (Exception)
{
}
}
}
listBox1.EndUpdate();
When you remove an item from an array that you are iterating over with the for..next statement, you should consider that every time you delete an element, the array count decrease of one element and every element in the array shifts at a lower index. So, when you delete the element at index 0, the previous element that were at index 1 shifts in position 0, but you have already iterated over the index zero, so you end skipping that element and trying to delete the element that was at index 2 before the removal of the item at index 0.
The solution is simple. Loop in reverse order (from highest element to lowest)
for (int i = listBox1.Items.Count-1; i >= 0 ; i--)
{
string filename = listBox1.Items[i].ToString();
if (File.Exists(filename))
{
File.Delete(filename);
listBox1.Items.Remove(filename);
}
}
Copy the contents of the listbox into a string array to prevent errors when remove the items from the listbox in looping.
// Copy the contents of the listbox into a string array
string[] filenameList = listBox1.Items.OfType<string>().ToArray();
try
{
for (int i = 0; i < filenameList.Length; i++)
{
string filename = filenameList[i];
if (File.Exists(filename))
{
File.Delete(filename);
listBox1.Items.Remove(filename);
}
}
}
catch (Exception)
{
}
I have a main List of Files Filelist.The Main List Contains Full File Paths and there is a second list copylist it is poupulated by fetching the contents from a directory.I need to replace the File Names in Filelist that matches with the ones in the temporary folder,so i used the following code.
Filelist = new List<string>();
//Code to Populate File List from openfiledialog
try
{
copylist = Directory.GetFiles(temppath + #"\mydir\");
List<string> tempfiles = new List<string>(Filelist);
int x = 0;
foreach (string file in tempfiles)
{
for (int i = 0; i < copylist .Length; i++)
{
if (Path.GetFileName(file) == Path.GetFileName(copylist [i]))
{
MessageBox.Show("Removed: " + file + " \ninserted:" + copylist [i]);
Filelist.RemoveAt(x);
Filelist.Insert(x,copylist [i]);
}
x++;
}
}
}
catch (Exception)
{
}
I tested with 4 files... The File names matched when i checked manually(ie: the same file name in temp folder and in the FileList).The equality check ie:Path.GetFileName(file) == Path.GetFileName(copylist [i]) is satisfied for just 2 files and finally only 1 file is replaced in Filelist even though all 4 files are present in temp folder.
What im i doing wrong.Please advice.
The logic of your program relies on the fact that positions in tempfiles and Filelist are related, and that x corresponds to the position of file in tempfiles. In order for this to work you need to add a break inside the if, and move x++ to the outside loop:
foreach (string file in tempfiles) {
for (int i = 0; i < copylist .Length; i++) {
if (Path.GetFileName(file) == Path.GetFileName(copylist [i])) {
MessageBox.Show($"Removed: {file}\ninserted:{copylist [i])}";
Filelist.RemoveAt(x);
Filelist.Insert(x,copylist[i]);
break; // << Added
}
}
x++; // << Moved
}
Once again I cannot find a solution myself (I have tried using Array.IndexOf(db, accnum) with a pos > -1 return boolean, but have reverted to this loop after I couldn't make it work).
So, I thought using db.Length would leave 'a' at the length of all the non-null elements in the array, however it seems to count the whole array, meaning that when the loop reaches a null element it causes an error. Is there a way to halt the loop count when it runs out of objects in the array?
void withdrawal()
{
int accnum;
double withdrawal;
//get and parse input details
accnum = int.Parse(tbNameEnt.Text);
withdrawal = double.Parse(tbBalaEnt.Text);
//check if account exists within existing objects
int a = db.Length;
for (int i = 0; i < a; i++)
{
if (db[i].GetAccNo() == accnum)
{
pos = i;
//deduct from balance
db[pos].SetBalance(db[pos].GetBalance() - withdrawal);
WithMess(); //success message
hide_form();
MakeWith2.Visible = false;
show_menu();
break;
}
else if ((db[i].GetAccNo() != accnum) && (i == db.Length - 1))
{
//account doesn't exist message
MessageBox.Show("Account does not exist");
}
}
}
If there are null items that pad the array.. break out of the loop when you reach one:
for (int i = 0; i < a; i++) {
if (db[i] == null)
break;
// the rest
Alternatively, use LINQ to filter the null items out:
foreach (var item in db.Where(x => x != null)) {
// loop here
}