I have a list and want to iterate smoothly through it while removing one element after another. I thought I could do it like this:
List<Point> open = new List<Point>();
...
while (!(open == null))
{
Point p = open.RemoveAt(0);
...
However, it is not quite working how I would like it to, starting with "Cannot implicitly convert type 'void' to 'Point'". But shouldn't the call of RemoveAt give the point to P before removing it/making it void?
List.RemoveAt does not return item which you are removing. Also list will not become null when you'll remove all items. It will become empty, i.e. with Count equal to 0. I would suggest you to use Queue<T> instead of List<T>. Thus you will be able to remove fist added item and get it at same time:
Queue<Point> open = new Queue<Point>();
while(open.Count > 0)
{
var point = open.Dequeue();
// ...
}
If you want to use list, and remove first items, then you should retrieve item by index, and only then remove it from list:
List<Point> open = new List<Point>();
while (open.Count > 0) // or open.Any()
{
Point p = open[0];
open.RemoveAt(0);
// ...
}
No, it does not. It does not return anything, as per the specification. Try using a Queue<Point> instead. Also, removing the first item in a List<T> does force a copy of the array-contents as far as I know (If somebody knows, please add relevant reference), so always avoid removing the first element in list and try to always find the best data structure to solve your particular issue!
Example:
var open = new Queue<Point>();
// ... Fill it
// Any() is in general faster than Count() for checking that collection has data
// It is a good practice to use it in general, although Count (the property) is as fast
// but not all enumerables has that one
while (open.Any()) {
Point p = open.Dequeue();
// ... Do stuff
}
Related
I using a ConcurrentBag as Collection that is thread safe, to avoid conflicts when i am updating my collection in differents threads.
But i notice that sometimes the itens get inverse, my firts item goes to the last position of my collection.
I just wanna know if this may be happening due to change the collection in concurrency. If it's not possible what could may be messing up my collection?
Edit: I'm adding some sample code.
When i need to add a item i make this:
var positionToInsert = (int)incremental.MDEntryPositionNo - 1;
concurrentList.ToList().Insert(positionToInsert, myListInfoToInsert);
In some cases i need to update a position so i do like this
var foundPosition = concurrentList.ToList()
.FirstOrDefault(orderBook => orderBook.BookPosition == incremental.MDEntryPositionNo);
var index = concurrentList.ToList().IndexOf(foundPosition);
if (index != -1)
{
concurrentList.ToList()[index] = infoToUpdate;
}
Thaks!
Edited: Just use sorting, don't use insertion it's a slow operation.
var orderedBooks = concurrentList.OrderBy(x=>x.BookPosition).ToList();
ConcurrentBag is implemented as a linked list, and the ToList code is shown below.
For each input thread, created own ThreadLocalList or reused free.
The head of a linked list is always the same, and I don't understand how the order can change in this situation. However you can't guarantee that the last item added won't be in the first bucket.
Please add your sample code.
private List<T> ToList()
{
List<T> objList = new List<T>();
for (ConcurrentBag<T>.ThreadLocalList threadLocalList = this.m_headList; threadLocalList != null; threadLocalList = threadLocalList.m_nextList)
{
for (ConcurrentBag<T>.Node node = threadLocalList.m_head; node != null; node = node.m_next)
objList.Add(node.m_value);
}
return objList;
}
I am working with an XML standard called SDMX. It's fairly complicated but I'll make it as short as possible. I am receiving an object called CategoryScheme. This object can contain a number of Category, and each Category can contain more Category, and so on, the chain can be infinite. Every Category has an unique ID.
Usually each Category contains a lot of Categories. Together with this object I am receiving an Array, that contains the list of IDs that indicates where a specific Category is nested, and then I am receiving the ID of that category.
What I need to do is to create an object that maintains the hierarchy of the Category objects, but each Category must have only one child and that child has to be the one of the tree that leads to the specific Category.
So I had an idea, but in order to do this I should generate LINQ queries inside a cycle, and I have no clue how to do this. More information of what I wanted to try is commented inside the code
Let's go to the code:
public void RemoveCategory(ArtefactIdentity ArtIdentity, string CategoryID, string CategoryTree)
{
try
{
WSModel wsModel = new WSModel();
// Prepare Art Identity and Array
ArtIdentity.Version = ArtIdentity.Version.Replace("_", ".");
var CatTree = JArray.Parse(CategoryTree).Reverse();
// Get Category Scheme
ISdmxObjects SdmxObj = wsModel.GetCategoryScheme(ArtIdentity, false, false);
ICategorySchemeMutableObject CatSchemeObj = SdmxObj.CategorySchemes.FirstOrDefault().MutableInstance;
foreach (var Cat in CatTree)
{
// The cycle should work like this.
// At every iteration it must delete all the elements except the correct one
// and on the next iteration it must delete all the elements of the previously selected element
// At the end, I need to have the CatSchemeObj full of the all chains of categories.
// Iteration 1...
//CatSchemeObj.Items.ToList().RemoveAll(x => x.Id != Cat.ToString());
// Iteration 2...
//CatSchemeObj.Items.ToList().SingleOrDefault().Items.ToList().RemoveAll(x => x.Id != Cat.ToString());
// Iteration 3...
//CatSchemeObj.Items.ToList().SingleOrDefault().Items.ToList().SingleOrDefault().Items.ToList().RemoveAll(x => x.Id != Cat.ToString());
// Etc...
}
}
catch (Exception ex)
{
throw ex;
}
}
Thank you for your help.
So, as i already said in my comment, building a recursive function should fix the issue. If you're new to it, you can find some basic information about recursion in C# here.
The method could look something like this:
private void DeleteRecursively(int currentRecursionLevel, string[] catTree, ICategorySchemeMutableObject catSchemeObj)
{
catSchemeObj.Items.ToList().RemoveAll(x => x.Id != catTree[currentRecursionLevel].ToString());
var leftoverObject = catSchemeObj.Items.ToList().SingleOrDefault();
if(leftoverObject != null) DeleteRecursively(++currentRecursionLevel, catTree, leftoverObject);
}
Afterwards you can call this method in your main method, instead of the loop:
DeleteRecursively(0, CatTree, CatSchemeObject);
But as i also said, keep in mind, that calling the method in the loop, seems senseless to me, because you already cleared the tree, besides the one leftover path, so calling the method with the same tree, but another category, will result in an empty tree (in CatSchemeObject).
CAUTION! Another thing to mention i noticed right now: Calling to list on your Items property and afterwards deleting entries, will NOT affect your source object, as ToList is generating a new object. It IS keeping the referenced original objects, but a deletion only affects the list. So you must write back the resulting list to your Items property, or find a way to directly delete in the Items object. (Assuming it's an IEnumerable and not a concrete collection type you should write it back).
Just try it out with this simple example, and you will see that the original list is not modified.
IEnumerable<int> test = new List<int>() { 1, 2, 3, 4 , 1 };
test.ToList().RemoveAll(a => a != 1);
Edited:
So here is another possible way of going after the discussion below.
Not sure what do you really need so just try it out.
int counter = 0;
var list = CatSchemeObj.Items.ToList();
//check before you call it or you will get an error
if(!list.Equals(default(list)))
{
while(true)
{
var temp = list.Where(x => CatTree[counter++] == x.Id); // or != ? play with it .
list = temp.Items.ToList().SingleOrDefault();
if(list.Equals(default(list))
{
break;
}
}
}
I just translated you problem to 2 solutions, but I am not sure if you won't lose data because of the SingleOrDefault call. It means 'Grab the first item regardless of everything'. I know you said you have only 1 Item that is ok, but still... :)
Let me know in comment if this worked for you or not.
//solution 1
// inside of this loop check each child list if empty or not
foreach (var Cat in CatTree)
{
var list = CatSchemeObj.Items.ToList();
//check before you call it or you will get an error
if(!list.Equals(default(list)))
{
while(true)
{
list.RemoveAll(x => x.Id != Cat.ToString());
list = list.ToList().SingleOrDefault();
if(list.Equals(default(list))
{
break;
}
}
}
}
//solution 2
foreach (var Cat in CatTree)
{
var list = CatSchemeObj.Items.ToList();
//check before you call it or you will get an error
if(!list.Equals(default(list)))
{
CleanTheCat(cat, list);
}
}
//use this recursive function outside of loop because it will cat itself
void CleanTheCat(string cat, List<typeof(ICategorySchemeMutableObject.Items) /*Place here whatever type you have*/> CatSchemeObj)
{
CatSchemeObj.RemoveAll(x => x.Id != cat);
var catObj = CatSchemeObj.Items.ToList().SingleOrDefault();
if (!catObj.Equals(default(catObj)){
CleanTheCat(cat, catObj);
}
}
Thank you to whoever tried to help but I solved it by myself in a much easier way.
I just sent the full CategoryScheme object to the method that converted it in the XML format, then just one line did the trick:
XmlDocument.Descendants("Category").Where(x => !CatList.Contains(x.Attribute("id").Value)).RemoveIfExists();
I have a two lists:
FPTStaticDataManagedStrategyAssetlist & FPTDocManagedStrategyList.
I want to be able to choose a random asset from FPTStaticDataManagedStrategyAssetlist, that doesn't already exist in FPTDocManagedStrategyList to stop duplicates.
This is my code currently
FPTStaticDataManagedStrategyAssetlist[random.Next(0, FPTStaticDataManagedStrategyAssetlist.Count())];
but obviously it can include duplicated items. Any Ideas?
You can use the Except method:
var temp = FPTStaticDataManagedStrategyAssetlist.Except(FPTDocManagedStrategyList).ToList();
if (temp.Count > 0)
{
var item = temp[random.Next(0, temp.Count)];
}
else
{
// no items to choose from...
}
You can also avoid materializing the result of Except to a list, by using the method posted by Jon Skeet here.
//Filter away duplicates
var listTemp = listA.Where(i=> !listB.Contains(i)).ToList();
//Select random
var randomItem = listTemp[random.Next(0, listTemp.Count())];
What I am trying to do is to implement a heuristic approach to NP complete problem: I have a list of objects (matches) each has a double score. I am taking the first element in the list sorted by the score desc and then remove it from the list. Then all elements bound to the first one are to be removed. I iterate through the list till I have no more elements.
I need a data structure which can efficiently solve this problem, so basically it should ahve the following properties:
1. Generic
2. Is always sorted
3. Has a fast key access
Right now SortedSet<T> looks like the best fit.
The question is: is it the most optimal choice for in my case?
List result = new List();
while (sortedItems.Any())
{
var first = sortedItems.First();
result.Add(first);
sortedItems.Remove(first);
foreach (var dependentFirst in first.DependentElements)
{
sortedItems.Remove(dependentFirst);
}
}
What I need is something like sorted hash table.
I assume you're not just wanting to clear the list, but you want to do something with each item as it's removed.
var toDelete = new HashSet<T>();
foreach (var item in sortedItems)
{
if (!toDelete.Contains(item))
{
toDelete.Add(item);
// do something with item here
}
foreach (var dependentFirst in item.DependentElements)
{
if (!toDelete.Contains(item))
{
toDelete.Add(dependentFirst);
// do something with item here
}
}
}
sortedItems.RemoveAll(i => toDelete.Contains(i));
I think you should use two data structures - a heap and a set - heap for keeping the sorted items, set for keeping the removed items. Fill the heap with the items, then remove the top one, and add it and all its dependents to the set. Remove the second one - if it's already in the set, ignore it and move to the third, otherwise add it and its dependents to the set.
Each time you add an item to the set, also do whatever it is you plan to do with the items.
The complexity here is O(NlogN), you won't get any better than this, as you have to sort the list of items anyway. If you want to get better performance, you can add a 'Removed' boolean to each item, and set it to true instead of using a set to keep track of the removed items. I don't know if this is applicable to you.
If im not mistake, you want something like this
var dictionary = new Dictionary<string, int>();
dictionary.Add("car", 2);
dictionary.Add("apple", 1);
dictionary.Add("zebra", 0);
dictionary.Add("mouse", 5);
dictionary.Add("year", 3);
dictionary = dictionary.OrderBy(o => o.Key).ToDictionary(o => o.Key, o => o.Value);
I have a String Collection that is populated with ID's like so -->
12345
23456
34567
and so on. What I need to do is at the user's request, and when certain parameters are met, go through that list, starting at the top, and perform a method() using that ID. If successful I would remove it from the list and move on.
I, embarrassingly, have never worked with a collection before in this manner. Can someone point me in the right direction. Examples all seem to be of the Console.Writeline(""); variety.
My base, ignorant, attempt looks like this -->
var driUps = Settings.Default.DRIUpdates.GetEnumerator();
while (driUps.MoveNext())
{
var wasSuccessfull = PerformDRIUpdate(driUps.Current);
if (wasSuccessfull)
{
driUps.Current.Remove(driUps.Current.IndexOf(driUps.Current));
}
}
The part I am most concerned with is the Remove(); Isn't there a better way to get the Current Index? Any and all Tips, Hints, Criticism, Pointers, etc....welcome. Thanks!
You are quite right to be concerned about the 'remove' during enumeration. How about somethign like this:
int idx = 0;
while (idx < strCol.Count)
{
var wasSuccessful = PerformDRIUpdate(strCol[idx]);
if (wasSuccessful)
strCol.RemoveAt(idx);
else
++idx;
}
As suggested by n8wrl, using RemoveAt solves the issue of trying to remove an item whilst enumerating the collection, but for large collections removing items from the front can cause performance issues as the underlying collection is re-built. Work your way from the end of the collection and remove items from that end:
//Loop backwards, as removing from the beginning
//causes underlying collection to be re-built
int index = (strCol.Count - 1);
while (index >= 0)
{
if (PerformDRIUpdate(strCol[index]))
{
strCol.RemoveAt(index);
}
--index;
}
Iterating an enumerator is best done with the foreach(), it does a GetEnumerator() and creates a similar block under the covers to what you're getting at, the syntax is:
foreach(ObjectType objectInstance in objectInstanceCollection)
{
do something to object instance;
}
for you,
List<DRIUpdate> updatesToRemove = new List<DRIUpdate>();
foreach(DRIUpdate driUpdate in Settings.Default.DRIUpdates)
{
if (PerformDRIUpdate(driUpdate))
{
updatesToRemove.Add(driUpdate);
}
}
foreach(DRIUpdate driUpdate in updatesToRemove)
{
Settings.Default.DRIUpdates.Remove(driUpdate);
}
If driUps is an IEnumerable<T>, try this:
driUps = driUps.Where(elem => !PerformDRIUpdate(elem));
Update:
From the example, it seems this is more appropriate:
Settings.Default.DRIUpdates =
Settings.Default.DRIUpdates.Where(elem => !PerformDRIUpdate(elem));
For a List<T>, it's simpler:
list.RemoveAll(PerformDRIUpdate);