For each with a dynamic list?
I have a for each loop that runs through the database to check for files that have been flagged for conversion. Currently I have the following code:
/* All files flagged for invidual conversion will be stored in here. */
ArrayList files = v开发者_如何学Goc.getFilesForInvidualConversion();
foreach (FileInfoExtended file in files)
{
// As long as the status flag hasn't been changed it can continue.
if (abort == false)
{
if (vc.isFileInUse(file) == false)
{
// Converting the video file.
vc.convertVideoToFLV(file);
}
}
vc.getFilesForInvidualConversion();
}
In the first line you can see I fill an ArrayList with objects which it will run through with a for each. However, after each file in the list I want to check for possible new files that need to be converted. When I fill the ArrayList again the for each doesn't seem to notice, it keeps working with the original files received from the first line of code. I'd rather want it to update the "files"-ArrayList so that it can convert the new files as well.
Is this possible?
EDIT: The anwsers you gave all work for this scenario, but I want to add something. Is it possible to remove a file from the list during the loop? And to make it so it won't convert that one?
EDIT 2: This is what I have now:
List<FileInfoExtended> files = vc.getFilesForInvidualConversion();
while (files.Count > 0)
{
if (abort == false)
{
if (vc.isFileInUse(files[0]))
{
vc.convertVideoToFLV(files[0]);
}
}
files = vc.getFilesForInvidualConversion();
}
And it works in both cases (when a file is added to the list and when a file is removed from the list). I don't know if it is performance wise a good solution, but right now it suits my needs. Unless there are some issues I'm overlooking?
Any comment will be appreciated! Kind regards, Floris
I would recommend using some other collection instead of ArrayList
. For example Stack<T>
. And write smth like this:
while (stack.Any())
{
var item = stack.Pop();
// convert item
}
// All items were converted
At any point you can stack.Push()
new items.
P.S.: Is there any point using non-generic ArrayList
?
You can use a standard 'for' loop. foreach loops require the collection to be immutable during traversal. A 'for' loop doesn't have this constraint. However, getting the ending condition constraints on a 'for' loop might be difficult in this case.
I would consider keeping a list of the files already processed so that when you make you second pass, you can just check to see if you have already handled a particular file.
The sane way to do this is to process batches: when each batch is done, get another batch until you hit an empty batch (this is the same approach suggested by @j0rd4n). Here's how you would wrap this logic up in a nice foreach
loop: first, create the class to manage the iteration:
namespace StackOverflow6128549
{
class FileInfoExtended
{
public int PropertyX { get; set; }
}
class IncrediblySmartIteration : IEnumerable<FileInfoExtended>
{
private List<FileInfoExtended> GetFilesToProcess()
{
throw new NotImplementedException();
}
#region IEnumerable<FileInfoExtended> Members
private IEnumerator<FileInfoExtended> InternalGetEnumerator()
{
List<FileInfoExtended> filesToProcess = null;
do
{
filesToProcess = GetFilesToProcess();
foreach (var fi in filesToProcess)
{
yield return fi;
}
}
while (filesToProcess.Count > 0);
}
public IEnumerator<FileInfoExtended> GetEnumerator()
{
return InternalGetEnumerator();
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return InternalGetEnumerator();
}
#endregion
}
}
You will then be able to run through objects of this type using a simple foreach
:
var container = new IncrediblySmartIteration();
foreach (var fi in container)
{
Console.WriteLine(fi.PropertyX);
}
Note that you should be concerned with guaranteeing termination when you design the GetFilesToProcess() method. Be sure to think about what will happen when there is an error looking for new files.
You could use recursion passing the index to the recursive function so that you can evaluate your location in the array.
void ConvertRecursively(int index, typeForVC vc)
{
if(abort)
return;
ArrayList files = vc.getFilesForInvidualConversion();
if(index !< files.Count)
return;
else
{
if (vc.isFileInUse(files[index]) == false)
{
// Converting the video file.
vc.convertVideoToFLV(files[index]);
}
return ConvertRecursive(++index, vc);
}
}
To call just do :
ConvertRecursively(0, typeForVC vc);
Update: if you need to handle case where the array decreases in size as well, also, the last flow control statement was unnecessary so I took it out:
void ConvertRecursively(int index, int prevSize, typeForVC vc)
{
if(abort)
return;
ArrayList files = vc.getFilesForInvidualConversion();
int sizeDifferential = files.Count <= prevSize ? prevSize - files.Count : 0;
int adjustedIndex = index - sizeDifferential;
if(adjustedIndex !< files.Count)
return;
if (vc.isFileInUse(files[adjustedIndex]) == false)
{
// Converting the video file.
vc.convertVideoToFLV(files[adjustedIndex]);
}
return ConvertRecursive(++adjustedIndex, files.Count, vc);
}
To call just do :
ConvertRecursively(0, 0, typeForVC vc);
Ok, so now I am just having fun with it. Hopefully it will work for you. I haven't tested this b.t.w.
精彩评论