I have a program that I used a variable of type List < MapPdf > that I will detach in variables when filling I would like to have the possibility to use it another time but I did not have the right to identify it again as
public static void Create(List<MapPdf> pps, Saison s, Agence agence)
{
foreach (var pelerins in grouped)
{
if (string.IsNullOrEmpty(pelerins.Key) || pelerins.Count() <= 0)
break;
if (writer.PageEvent == null)
{
writer.PageEvent = new Header_List()
{
travel = ctx.Travels.Include("Transport").First(v => v.UniqueId == pelerins.Key),
travelretour = ctx.Travels.Find(pelerins.First().UniqueIdRetour),
Agence = agence,
CountAllPelerin = pelerins.Count().ToString(),
CountFeminin = pelerins.Count(x => x.Sexe == PelerinSexe.Feminin).ToString(),
CountMasculin = pelerins.Count(x => x.Sexe == PelerinSexe.Masculin).ToString(),
NomGroupe = pelerins.First().Groupe,
NumeroDoc = writer.PageNumber
};
}
}
}
And i want to use pelerins as a List when i used in another function when it is of this declaration
I used List < MapPdf > pls = pelerins.ToList(); but it does not work
CreateFr(pls, false, cb, s);
If you are referring to var pelerins within the for-each loop and if I understand the problem, you are unable use it into another method , because var pelerins is a local variable encapsulated within the for-each loop -It does not exist outside it.
You could do the following:
//public property to retrieve pelerins
public List <MapPdf> pls new List<MapPdf>();
...
...
public static void Create(List<MapPdf> pps, Saison s, Agence agence)
{
foreach (var pelerins in grouped)
{
if (string.IsNullOrEmpty(pelerins.Key) || pelerins.Count() <= 0)
break;
if (writer.PageEvent == null)
{
//do logic
...
//store the one you are interested in, so you can use it later on
pls = pelerins.ToList();
}
}
}
Related
I have a method called clearFiles which can be called recursively if there is sub directories. I have created a counter that will count the number of files that have been deleted. The counter holds the correct number when the function is either called once or called recursively but the toast at the end of the function only returns the correct number when it is not called recursively. Is there anyway I can display the toast and then reset the number of filesCleared? Because it's just returning a 0 when it's called recursively.
From playing around with it for a bit it seems like the toast is getting called after the filesCleared variable is set to 0 which is not what I want.
filesCleared variable:
int filesCleared = 0;
clearFiles:
public async Task ClearFiles()
{
var pathName = FileFilter.PathName;
FileInfo[] files = SortFiles(pathName);
try
{
if(FileFilter.Filter == "all")
{
foreach(var file in files)
{
if(file.Extension == FileFilter.Extension || FileFilter.Extension == "all")
{
File.Delete(file.ToString());
filesCleared++;
}
}
}
if(FileFilter.Filter == "date")
{
foreach (var file in files) //regular files
{
if(file.CreationTime < FileFilter.DeleteDate) //based on time
{
if(file.Extension == FileFilter.Extension || FileFilter.Extension == "all") //based on extension
{
File.Delete(file.ToString());
filesCleared++;
}
}
}
}
if(FileFilter.Filter == "number")
{
var i = 0;
for(var j = files.Length-1; j >= 0 ; j--)
{
if(files[j].Extension == FileFilter.Extension || FileFilter.Extension == "all")
{
if(i++ >= FileFilter.FilesToKeep)
{
File.Delete(files[j].ToString());
filesCleared++;
}
}
}
}
if (FileFilter.SubFolders == true) //subfiles (will be called recursively w/ each filter)
{
foreach(var subDir in new DirectoryInfo(pathName).GetDirectories())
{
//subDir.Delete(true);
FileFilter.PathName = subDir.ToString();
ClearFiles();
//await ClearFiles(subDir.ToString());
}
FileFilter.PathName = pathName; //resets the pathName so it will go back to what it was before the recursion
}
}
catch (IOException ioExp)
{
Console.WriteLine(ioExp.Message);
Toast = Toast.Bad();
logger.LogError(ioExp, "Error Deleting");
}
Toast = Toast.Good(filesCleared + " Files Deleted");
filesCleared = 0;
}
If you want to do something once but also want to call a method recursively, you have to split it in two. After trying to simplify your code I get a ClearFiles method like this:
public void ClearFiles()
{
var filesCleared = 0;
try
{
filesCleared = DeleteFilesRecursively(FileFilter.PathName, FileFilter);
}
catch (IOException ioExp)
{
Console.WriteLine(ioExp.Message);
Toast = Toast.Bad();
logger.LogError(ioExp, "Error Deleting");
}
Toast = Toast.Good(filesCleared + " Files Deleted");
}
Now Toast.Good is only called once after all subfolders have been traversed.
Note that filesCleared is a local variable, since I don't see any point in making it global. That way you also don't need to reset it.
The implementation of DeleteFilesRecursively could be something like this and could be simplified more if you wanted:
private const string All = "all";
private const string FilterByDate = "date";
private const string FilterByNumber = "number";
int DeleteFilesRecursively(string dirPath, SomeFileFilterType fileFilter)
{
FileInfo[] files = SortFiles(dirPath);
var deleted = 0;
var toBeDeleted = files.Where(f => MatchesByExtension(f, fileFilter.Extension));
if (fileFilter.Filter == FilterByDate)
{
toBeDeleted = toBeDeleted.Where(f => MatchesByDate(f, fileFilter.DeleteDate));
}
else if (FileFilter.Filter == FilterByNumber)
{
// If your SortFiles method sorted in the other
// direction this call to Reverse would not be needed.
toBeDeleted = toBeDeleted.Reverse().Take(fileFilter.FilesToKeep);
}
foreach (var file in toBeDeleted)
{
File.Delete(file.ToString());
deleted++;
}
if (fileFilter.SubFolders)
{
foreach(var subDir in new DirectoryInfo(dirPath).GetDirectories())
{
deleted += DeleteFilesRecursively(subDir.FullName, fileFilter);
}
}
return deleted;
}
bool MatchesByExtension(FileInfo file, string extension)
=> file.Extension == extension || extension == All;
bool MatchesByDate(FileInfo file, DateTime deleteDate)
=> file.CreationTime < deleteDate;
Note that I also removed your magic strings, which could be even better by replacing them with an enum type.
I haven't tested this but I believe it should give you the same behavior as your current code (at least the parts about filtering and deleting).
I am working on a function which will modify the input payload properties. The payload contains nodes and each node contains list of features. I need to remove some specific features match condition and also modify each node window property start and end time. I have written the function using traditional nested for loop, but struggling to convert it to Linq function. Anyone has idea how to convert this nested for loop function to a Linq function?
private void ApplyTransformation(InputPayload payload, int startTime = 8, int endTime = 15)
{
var nodes = payload.Nodes;
for (var i = 0; i < nodes.Count(); ++i)
{
var node = nodes[i];
var features = node.Features;
for (var j = 0; j < features.Count(); ++j)
{
var feature = features[j];
if (feature.NodeFeatureTypeID
== FeatureTypeEnum.FEATURE_A
|| feature.FeatureTypeID == FeatureTypeEnum.FEATURE_B
|| feature.FeatureTypeID == FeatureTypeEnum.FEATURE_C
|| feature.FeatureTypeID == FeatureTypeEnum.FEATURE_D
)
{
features.RemoveAt(j);
}
}
var windows = node.Windows;
for (var k = 0; k < windows.Count(); ++k)
{
var window = windows[k];
if (window.NodeFunctionTypeID == FeatureTypeEnum.MM_HOURS) continue;
window.StartHour = new TimeSpan(startTime, 0, 0);
window.EndHour = new TimeSpan(endTime, 0, 0);
}
}
}
Let's do it in parts. This first code of yours removes features that are in a list,
for (var j = 0; j < features.Count(); ++j)
{
var feature = features[j];
if (feature.NodeFeatureTypeID
== FeatureTypeEnum.FEATURE_A
|| feature.FeatureTypeID == FeatureTypeEnum.FEATURE_B
|| feature.FeatureTypeID == FeatureTypeEnum.FEATURE_C
|| feature.FeatureTypeID == FeatureTypeEnum.FEATURE_D
)
{
features.RemoveAt(j);
}
}
We need to convert that to "keep features not in a list"
var discard = new [] {FeatureTypeEnum.FEATURE_A, FeatureTypeEnum.FEATURE_B, FeatureTypeEnum.FEATURE_C, FeatureTypeEnum.FEATURE_D };
node.Features = node.Features.Where(f => !discard.Contains(f)).ToArray();
This part of your code skips if function type is a certain kind, and zeroes timespans if the function type is not a certain kind:
if (window.NodeFunctionTypeID == FeatureTypeEnum.MM_HOURS) continue;
window.StartHour = new TimeSpan(startTime, 0, 0);
window.EndHour = new TimeSpan(endTime, 0, 0);
Which might be better as a loop that operates on just those things we are interested in (we want to modify only those Windows where the nodefuctionTypeId is not Hours):
foreach(var window in node.Windows.Where(w => w.NodeFunctionTypeID != FeatureTypeEnum.MM_HOURS){
window.StartHour = new TimeSpan.FromHous(startTime);
window.EndHour = new TimeSpan.FromHours(endTime);
}
Meaning the whole is:
private void ApplyTransformation(InputPayload payload, int startTime = 8, int endTime = 15)
{
var discard = new [] {FeatureTypeEnum.FEATURE_A, FeatureTypeEnum.FEATURE_B, FeatureTypeEnum.FEATURE_C, FeatureTypeEnum.FEATURE_D };
foreach (var node in payload.Nodes)
{
node.Features = node.Features.Where(f => !discard.Contains(f)).ToArray();
foreach(var window in node.Windows.Where(w => w.NodeFunctionTypeID != FeatureTypeEnum.MM_HOURS){
window.StartHour = TimeSpan.FromHous(startTime);
window.EndHour = TimeSpan.FromHours(endTime);
}
}
}
I don't think I'd convert it all to a Linq form, as it would make a mess; linq queries should not have side effects (modify the objects the query iterates over) so particularly the second part where the time spans are being zeroed would have to become an operation where everything about the window was being copied over to a new Window if you wanted to LINQ it.
If a window is literally just a time span pair then it's not so bad, or if you want to provide a constructor that takes an existing Window and a startTime and endTime:
public Window(Window copyFrom, int startTime, int endTime){
this.X = copyFrom.X;
this.Y = copyFrom.Y;
...
this.StartHour = TimeSpan.FromHours(strtTime);
this.EndHour = TimeSpan.FromHours(endTime);
}
Then maybe your method could become some linq:
foreach (var node in payload.Nodes)
{
node.Features = node.Features.Where(f => !discard.Contains(f)).ToArray();
node.Windows = node.Windows.Select(w => w.NodeFunctionTypeID == FeatureTypeEnum.MM_HOURS ? w : new Window(w, startTime, endTime).ToArray();
}
..but I don't know if I would try for a wholesale replacement of the entire nodes list, for reasons even based on the name of the method: ApplyTransformations sounds like it means "take this list of nodes and change bits of them" not "take this list of nodes and give me a new list with some or all of the nodes replaced or modified" - that sort of behavior in code could wreck something else, if the calling code is expecting a tweak and the object it sends (or objects within it) are swapped out for new ones
Using a linq query for the second part would make things messier, better to just have a for loop
Something like this should work:
var nodes = payload.Nodes;
nodes.Features = nodes.Features.Where(f => !(
f.NodeFeatureTypeID == FeatureTypeEnum.FEATURE_A
|| feature.FeatureTypeID == FeatureTypeEnum.FEATURE_B
|| feature.FeatureTypeID == FeatureTypeEnum.FEATURE_C
|| feature.FeatureTypeID == FeatureTypeEnum.FEATURE_D
)
);
foreach(var window in nodes.Windows)
{
if (window.NodeFunctionTypeID != FeatureTypeEnum.MM_HOURS)
{
window.StartHour = new TimeSpan(startTime, 0, 0);
window.EndHour = new TimeSpan(endTime, 0, 0);
}
}
Pls have look at below code snippet to avoid nested loop using linq.
public class Employee
{
public string Name { get; set; }
public List<EmployeeProject> EmployeeProject { get; set; }
}
public class EmployeeProject
{
public string ProjectName { get; set; }
public string ClientName { get; set; }
}
/// <summary>
/// Object mapping
/// </summary>
/// <returns></returns>
public static List<Employee> CreateObject()
{
var employeeList = new List<Employee>();
var employee = new Employee();
var employeeProjectList = new List<EmployeeProject>();
employee.Name = "John";
var employeeProject = new EmployeeProject();
employeeProject.ProjectName = "Chrome";
employeeProject.ClientName = "Google";
employeeProjectList.Add(employeeProject);
employeeProject = new EmployeeProject();
employeeProject.ProjectName = "WhatsApp";
employeeProject.ClientName = "Meta";
employeeProjectList.Add(employeeProject);
employee.EmployeeProject = employeeProjectList;
employeeList.Add(employee);
employee.Name = "Alex";
employeeProjectList = new List<EmployeeProject>();
employeeProject = new EmployeeProject();
employeeProject.ProjectName = "Chrome2";
employeeProject.ClientName = "Google2";
employeeProjectList.Add(employeeProject);
employeeProject = new EmployeeProject();
employeeProject.ProjectName = "WhatsApp2";
employeeProject.ClientName = "Meta2";
employeeProjectList.Add(employeeProject);
employee.EmployeeProject = employeeProjectList;
employeeList.Add(employee);
return employeeList;
}
/// <summary>
/// Linq function
/// </summary>
public static void LinqFunctionForNestedQuery()
{
var employeeObject = CreateObject();
var result1 = employeeObject.Select(x =>
{
x.EmployeeProject = x.EmployeeProject.Select(y =>
{
y.ProjectName.Contains("Chrome");
return y;
}).ToList();
return x;
});
}
To maintain readability of the code and to make it simpler , I have modified the code.
Step1 : Replace for with foreach if you can
Step2 : Replace foreach with linq
Important tip. Resharper helps you with code suggestions.
Solution
private void ApplyTransformation(InputPayload payload, int startTime = 8, int endTime = 15)
{
foreach (var node in payload.Nodes)
{
var features = node.Features;
foreach (var feature in features.Where(feature => feature.NodeFeatureTypeID == FeatureTypeEnum.FEATURE_A ||
feature.FeatureTypeID == FeatureTypeEnum.FEATURE_B ||
feature.FeatureTypeID == FeatureTypeEnum.FEATURE_C ||
feature.FeatureTypeID == FeatureTypeEnum.FEATURE_D))
{
features.Remove(feature);
}
var windows = node.Windows;
foreach (var window in windows
.Where(window => window.NodeFunctionTypeID != FeatureTypeEnum.MM_HOURS))
{
window.StartHour = new TimeSpan(startTime, 0, 0);
window.EndHour = new TimeSpan(endTime, 0, 0);
}
}
}
I have the following list,
String UpDownStatus = "UP";
List<db1> StockData = new List<db1>();
db1 newStock = new db1();
newStock.Date = (DateTime)reader["Date"];
newStock.High = (double)reader["High"];
newStock.Low = (double)reader["Low"];
newStock.Close = (double)reader["Close"];
newStock.Up_Down = (string)reader["Up_Down"];
StockData.Add(newStock);
The Up_Down column in my DB has the following two string : "UP" and "DOWN"
how can i compare whether the current value of
for (int i = 0; i < StockData.Count; i++)
{
if(StockData[i].Up_Down.CompareTo(UpDownStatus) != 0)
{
//do something
}
}
I know, i could reframe this statement like if (StockData[i].Up_Down=="UP") but i need a solution where I could use .CompareTo function.
If I understood your question right and you want to do something on all items which have the same up/down-status as the variable UpDownStatus, this would be the easiest way to do it:
foreach (var item in StockData.Where(e => e.Up_Down == UpDownStatus))
{
// do something
}
I have a list of items in a list. From that list I need to take the first 1000 items and need to submit the package and then again I need to take another 1000 and need to submit a package. If the list is not having 1000 I need to submit the package with all the items. for that I wrote the following code which is returning an error as collection modified.
List<SyncQueue> tempMassiveSyncQueue=massiveSyncQueue;
while (tempMassiveSyncQueue.Count != 0)
{
int MassivePackageFileCount =Convert.ToInt32(ConfigurationManager.AppSettings["MassivePackageFileLimit"]);
massiveSyncQueues = tempMassiveSyncQueue;
List<SyncQueue> tempMassivePackageSyncQueue=new List<SyncQueue>();
if (massiveSyncQueues.Count > 1000
{
var massivePackageSyncQueue = (massiveSyncQueues.Take(1000)).ToList<SyncQueue>();
tempMassivePackageSyncQueue = massivePackageSyncQueue;
SubmitPackage(massivePackageSyncQueue);
}
if (tempMassivePackageSyncQueue.Count != 0)
{
foreach (var massivesynq in tempMassiveSyncQueue)
{
foreach (var deleteId in tempMassivePackageSyncQueue.Where(id => id.SyncQueueId == massivesynq.SyncQueueId))
{
tempMassiveSyncQueue.Remove(massivesynq);
}
}
}
else
{
SubmitPackage(massiveSyncQueues);
}
massiveSyncQueues = null;
}
Can any one help on this?
Incorporate Skip into your logic
int loopCount = 0;
While(true)
{
var ListToProcess = massiveSyncQueue.Skip(loopCount*1000).Take(1000);
SubmitPackage(ListToProcess);
if(ListToProcess.Count < 1000) // We know there are no more in the list massive list.
{
break;
}
loopCnt++;
}
Your problem is that you are adjusting the collection on which the bounds of the foreach construct are set.
Try using ToList() on the collection you are looping through, as this creates a new List in memory:
foreach (var massivesynq in tempMassiveSyncQueue.ToList())
{
foreach (var deleteId in tempMassivePackageSyncQueue.Where(id => id.SyncQueueId == massivesynq.SyncQueueId).ToList())
{
tempMassiveSyncQueue.Remove(massivesynq);
}
}
In line 1 you set tempMassiveSyncQueue = massiveSyncQueue, yet within the while loop you set massiveSyncQueue = tempMassiveSync.
The collection modified error usually occurs when you modify the collection you are looping through. Which is why you need to first create a copy of the collection which is INDEPENDANT to the original collection and loop through that.
Before the while loop you need to add all items in massiveSyncQueue to tempMassiveSyncQueue. You then need to loop through the temp list with your code. In the second loop, you are removing items from the list you are looping through. I assume you meant to remove the items from massiveSyncQueue and not the temp list.
Try the following:
List<SyncQueue> tempMassiveSyncQueue = new List<SyncQueue>();
foreach(var item in massiveSyncQueue)
{
tempMassiveSyncQueue.Add(item);
}
while (tempMassiveSyncQueue.Count != 0)
{
int MassivePackageFileCount = Convert.ToInt32(ConfigurationManager.AppSettings["MassivePackageFileLimit"]);
List<SyncQueue> tempMassivePackageSyncQueue=new List<SyncQueue>();
if (massiveSyncQueues.Count > 1000
{
var massivePackageSyncQueue = (massiveSyncQueues.Take(1000)).ToList<SyncQueue>();
tempMassivePackageSyncQueue = massivePackageSyncQueue;
SubmitPackage(massivePackageSyncQueue);
}
if (tempMassivePackageSyncQueue.Count != 0)
{
foreach (var massivesynq in massiveSyncQueue)
{
foreach (var deleteId in tempMassivePackageSyncQueue.Where(id => id.SyncQueueId == massivesynq.SyncQueueId))
{
massiveSyncQueue.Remove(massivesynq);
}
}
}
else
{
SubmitPackage(massiveSyncQueues);
}
massiveSyncQueues = null;
}
Try this
int count=1;
while(tempMassivePackageSyncQueue.Count>1000)
{
var massivePackageSyncQueue = (massiveSyncQueues.skip(count*1000).Take(1000)).ToList<SyncQueue>();
tempMassivePackageSyncQueue = massivePackageSyncQueue;
SubmitPackage(massivePackageSyncQueue);
count++;
}
var massivePackageSyncQueue = (massiveSyncQueues.skip(count*1000).Take()).ToList<SyncQueue>();
tempMassivePackageSyncQueue = massivePackageSyncQueue;
SubmitPackage(massivePackageSyncQueue);
This question already has answers here:
How to remove elements from a generic list while iterating over it?
(28 answers)
Closed 9 years ago.
My goal is to delete a user from the user list in my application.But i cannot get to the bottom of this error. Some one plz bail me out.
if (txtEmailID.Text.Length > 0)
{
users = UserRespository.GetUserName(txtEmailID.Text);
bool isUserAvailable=false;
foreach (EduvisionUser aUser in users) // Exception thrown in this line
{
isUserAvailable = true;
if(!aUser.Activated)
{
users.Remove(aUser);
}
}
if (users.Count == 0 && isUserAvailable)
{
DeactivatedUserMessage();
return;
}
}
You can't modify a collection while you're iterating over it with a foreach loop. Typical options:
Use a for loop instead
Create a separate collection of the items you want to act on, then iterate over that.
Example of the second approach:
List<EduvisionUser> usersToRemove = new List<EduvisionUser>();
foreach (EduvisionUser aUser in users) --->***Exception thrown in this line***
{
isUserAvailable = true;
if(!aUser.Activated)
{
usersToRemove.Add(aUser);
}
}
foreach (EduvisionUser userToRemove in usersToRemove)
{
users.Remove(userToRemove);
}
Another alternative, if you're using List<T> is to use List<T>.RemoveAll:
isUserAvailable = users.Count > 0;
users.RemoveAll(user => !user.Activated);
You are trying to delete a user from the list you are looping trough.
this is impossible. Best is to create a new list and add the good ones in it instead of deleting the bad ones
if (txtEmailID.Text.Length > 0)
{
//#new list
List<EduvisionUser> listOfAcceptedUsers = new List<EduvisionUser>()**
users = UserRespository.GetUserName(txtEmailID.Text);
bool isUserAvailable=false;
foreach (EduvisionUser aUser in users) --->***Exception thrown in this line***
{
isUserAvailable = true;
//Add user to list instead of deleting
if(aUser.Activated)
{
ListOfAcceptedUsers.Add(aUser);
}
}
//check new list instead of old one
if (ListOfAcceptedUsers.Count == 0 && isUserAvailable)
{
DeactivatedUserMessage();
return;
}
}
you can do it like this. Use for instead foreach
for( int i =0; i< users.Count; i++ ) --->***Exception thrown in this line***
{
EduvisionUser aUser = users[i];
isUserAvailable = true;
if(!aUser.Activated)
{
users.Remove(aUser);
i--;
}
}
You cannot modify the collection while enumerating. Instead of removing select only what you need and leave the Garbage Collector take care of the rest:
users = users.Where(x => x.Activated);
Or even better, select only what you need from the repository:
users = UserRespository.GetUserName(txtEmailID.Text).Where(x => x.Activated);
My goal is to delete a WorkCalendar from the WorkCalendar but when select Wc that has WorkHour thrown an exception like this:" Collection was modified; enumeration operation may not execute." Any ideas? thanks for the help
Delete method:
try
{
if (!this.DataWorkspace.ApplicationData.WorkCalendars.CanDelete)
{
this.ShowMessageBox("", "", MessageBoxOption.Ok);
return;
}
if (this.WorkCalendars.SelectedItem != null)
{
if ((this.WorkCalendars.SelectedItem.FindCalendarWPs.Count() > 0) || (this.WorkCalendars.SelectedItem.FindCalendarWPs1.Count() > 0))
{
Microsoft.LightSwitch.Threading.Dispatchers.Main.BeginInvoke
(() =>
{
RadWindow.Alert(" ");
});
return;
}
var y = DataWorkspace.ApplicationData.WorkCalendarDays.Where(w => w.WorkCalendar.Id == WorkCalendars.SelectedItem.Id).Execute().AsEnumerable();
foreach (var item in y)
{
if(item.WorkingHoursCollection != null && item.WorkingHoursCollection.Count() > 0)
foreach (var WH in item.WorkingHoursCollection)
{
WH.Delete();
}
item.Delete();
}
if (this.WorkCalendars.SelectedItem == this.DataWorkspace.ApplicationData.WorkCalendars.Where(U => U.Id == this.WorkCalendars.SelectedItem.Id).SingleOrDefault())
{
Microsoft.LightSwitch.Threading.Dispatchers.Main.BeginInvoke
(() =>
{
RadWindow.Alert(" ");
});
return;
}
this.WorkCalendars.SelectedItem.Delete();
this.Save();
}
}
catch (Exception ex)
{
Microsoft.LightSwitch.Threading.Dispatchers.Main.BeginInvoke
(() =>
{
var msg = new LightSwitchApplication.Presentation.GeneralViews.ExceptionMessage();
msg.DataContext = ex;
msg.ShowDialog();
});
}