Recursive algorithm for adding items into a list - c#

I am having some problems writing a recursive algorithm.
I have an item that affects other items.
Each of the affected items might affect other items...etc.
With a limited number of steps I might write:
var tempAffected = new List<Item>();
foreach(var item2 in item1.affectedItems)
{
if(item2.affectedItems > 0)
{
foreach(var item3 in item2.affectedItems)
{
if(item3.affectedItems > 0)
{
...
tempAffected.AddRange(item3.affectedItems)
tempAffected.Add(item3);
}
else
tempAffected.AddItem(item3);
}
}
else
tempAffected.AddItem(item2);
}
But I would like something recursive.
Any help would be appreciated.
EDIT
The final code ended up looking like this, after a few modifications in my code.
var tempAffected = new List<HSGameItem>();
var stack = new Stack<HSGameItem>(affected);
Func<HSGameItem, List<HSGameItem>> affectedForItem = item => {
if (item.booster.accounted)
return new List<HSGameItem> ();
item.booster.accounted = true;
return item.booster.affected;
};
while(stack.Count > 0)
{
var childrenParent = stack.Pop();
foreach (var child in affectedForItem(childrenParent))
{
tempAffected.AddUnique(child);
stack.Push(child);
}
}
tempAffected.ForEach(x => x.state.Matched(mType, length));
I had to mark every item that i already affected as "accounted" to make sure i wouldn't check it again.

So basically you want to collect all affected items into a temporary list called TempAffected, right?
Then you could do:
public List<Item> tempAffected = new List<Item>();
AddAffectedToDerived(item1, tempAffected);
private AddAffectedToDerived(Item root, List<Item> derived)
{
if (root.AffectedItems != null)
{
foreach(Item itemX in root.AffectedItems)
{
AddAffectedToDerived(itemX);
}
}
derived.Add(root);
}
That should do the trick for you.
Mind you, if your data structures are very large, you may want to use an iterative approach rather than a recursive instead because of the risk of stack overflow.

IMHO, the simplest implementation might look something like this:
IEnumerable<Item> GetAffectedItems(Item item)
{
foreach (Item affectedItem in item.affectedItems)
{
foreach (Item subItem in GetAffectedItems(affectedItem))
{
yield return subItem;
}
}
yield return item;
}
That said, note that the above will instantiate a large number of iterators (but at least that's better than creating a lot of copies of the data itself!). It's simple to write, but may not be as efficient as some other mechanism for enumerating all of the affected items.
As an example, an alternative would be to just build a List<Item> as you recurse (more similar to your original example):
List<Item> GetAffectedItems(Item item)
{
List<Item> list = new List<Item>();
GetAffectedItems(item, list);
return list;
}
void GetAffectedItems(Item item, List<Item> list)
{
foreach (Item affectedItem in item.affectedItems)
{
GetAffectedItems(affectedItem, list);
}
list.Add(item);
}

Related

Removing elements from a local data structure effects the parent object

I have the following code where I am checking if some elements are not matching in my dictionary then I want to remove the unmatching elements from the local item. The problem is, When a value is removed from the collection, for some reason it also modifies the parental structure.
My other problem is, for example if I have list as "A","B","B", using the Except is only giving me the single B but not the other. Please help.
public void AddLogs(IEnumerable<ReportGenerationTypes> subElements)
{
var changeDetails = new Dictionary<AuditSaveHeader, List<string>>();
List<string> AuditableItems = null;
List<string> subItems = new List<string>();
foreach (var item in subElements)
{
subItems.Add(item.ToString());
}
foreach (var item in auditLogData?.AuditHeaders)
{
if (!changeDetails.ContainsKey(item))
{
changeDetails.Add(item, null);
}
AuditableItems = new List<string>();
foreach (var inner in item.AuditChangeValues)
{
AuditableItems.Add(inner.Auditable.ToString());
}
changeDetails[item] = AuditableItems;
}
for (int i = 0; i < changeDetails.Count; i++)
{
var result = kp.Value.Except(subItems);
Auditable AuditItem = Auditable.Unassigned;
//I think the problem lies with the below code not sure.
if (result != null && result.Count() > 0)
{
foreach (var item in result)
{
Enum.TryParse(item, out AuditItem);
var itemToRemove = kp.Key.AuditChangeValues.Where(x => x.Auditable == AuditItem).FirstOrDefault();
//The following line effects the AuditChangeValues object and not just my dictionary.
kp.Key.AuditChangeValues.Remove(itemToRemove);
}
}
}
}
Promoting my comment to answer:
You are using some vars that are not shown, like kp, auditLogData, etc. and overall is not clear what you want to achieve.
Anyway I agree the problem is you are editing the reference to an object. You could try cloning the objects, etc. But without really understanding the code is hard to tell.

Query too large mongodb c#

I`m trying to make a query in robomongo but there seems to be too many results in the query.
List<DataObject> list = collection.FindAs<DataObject>(Query.EQ("Item1", "Value1")).ToList();
foreach (DataObject item in list)
{
//Do Something
}
From what i read, i would need to use MongoCursor, but I couldnt find a good example, is there iterate through everything using batches of 1000?
Something like:
MongoCursor<DataObject> cursor = collection.FindAs<DataObject>(Query.EQ("Item1", "Value1"));
int batchNumber = 1000;
List<DataObject> list;
while(list = cursor.getBatch(batchNumber);)
{
foreach (DataObject item in list)
{
//Do Something
}
}
Now I understood i could easily solve this if i dont save it in a list before the foreach by doing :
foreach (DataObject item in collection.FindAs<DataObject>(Query.EQ("Item1", "Value1")))
{
//Do Something
}
This was solved by not saving the result in a list before the foreach. Like this
foreach (DataObject item in collection.FindAs<DataObject>(Query.EQ("Item1", "Value1")))
{
//Do Something
}

Is there a concurrent sorted dictionary or something similar?

For a project we've been working on we used a concurrent dictionary, which was fine until a new specification came up which required the dictionary to be sorted (it should remain in the order it was added, kind of like a FIFO).
This is currently what we do, we take an x amount (5 in this case) of items out of the dictionary:
private Dictionary<PriorityOfMessage, ConcurrentDictionary<Guid, PriorityMessage>> mQueuedMessages = new Dictionary<PriorityOfMessage, ConcurrentDictionary<Guid, PriorityMessage>>();
var messages = new List<KeyValuePair<Guid, PriorityMessage>>();
messages.AddRange(mQueuedMessages[priority].Take(5));
then we do some things with it and eventually if everything succeeds we removed them.
mQueuedMessages[priority].TryRemove(messageOfPriority.Key);
However if things fail we won't remove them and try later. So unfortunatly there is no concurrent sorted dictionary, but are there ways to ensure the messages stay in the order they are added?
It is very important we can take multiple objects from the list/dictionary without removing them (or we need to be able to add them to the front later).
How often will you take per second?
.
it could be a thousand times a second
1000 lock operations per second are absolutely nothing. This will consume almost no time at all.
my colleague has already tried using locks and lists and he deemed it too slow
In all likelihood this means that the locked region was too big. My guess is it went something like that:
lock (...) {
var item = TakeFromQueue();
Process(item);
DeleteFromQueue(item);
}
This does not work because Process is too slow. It must be:
lock (...)
var item = TakeFromQueue();
Process(item);
lock (...)
DeleteFromQueue(item);
You will not have any perf problems with that at all.
You can now pick any data structure that you like. You are no longer bound by the capabilities of the built-in concurrent data structures. Besides picking a data structure that you like you also can perform any operation on it that you like such as taking multiple items atomically.
I have not fully understood your needs but it sounds like SortedList might go in the right direction.
You could also go for another solution (haven't tested it performance-wise):
public class ConcurrentIndexableQueue<T> {
private long tailIndex;
private long headIndex;
private readonly ConcurrentDictionary<long, T> dictionary;
public ConcurrentIndexableQueue() {
tailIndex = -1;
headIndex = 0;
dictionary = new ConcurrentDictionary<long, T>();
}
public long Count { get { return tailIndex - headIndex + 1; } }
public bool IsEmpty { get { return Count == 0; } }
public void Enqueue(T item) {
var enqueuePosition = Interlocked.Increment(ref tailIndex);
dictionary.AddOrUpdate(enqueuePosition, k => item, (k, v) => item);
}
public T Peek(long index) {
T item;
return dictionary.TryGetValue(index, out item) ?
item :
default(T);
}
public long TryDequeue(out T item) {
if (headIndex > tailIndex) {
item = default(T);
return -1;
}
var dequeuePosition = Interlocked.Increment(ref headIndex) - 1;
dictionary.TryRemove(dequeuePosition, out item);
return dequeuePosition;
}
public List<T> GetSnapshot() {
List<T> snapshot = new List<T>();
long snapshotTail = tailIndex;
long snapshotHead = headIndex;
for (long i = snapshotHead; i < snapshotTail; i++) {
T item;
if (TryDequeue(out item) >= 0) {
snapshot.Add(item);
}
}
return snapshot;
}
}

Alternatives to nested foreach when comparing list contents based on some (not all) property values

As part of this question, it was pointed out repeatedly that I had an O(n^2) problem using code similar to this...
public class Foo
{
public string IdentityValue {get;set;}
public string Prop1 {get;set;}
public string Prop2 {get;set;}
}
List<Foo> itemSet1 = GenerateLargeItemSet(); //makes a large list, > 5000 items for example
List<Foo> itemSet2 = GenerateLargeItemSet();
foreach (var itemFromSet1 in itemSet1)
{
//does a corresponding item exist in itemSet2?
var itemSet2Item = itemSet2.FirstOrDefault(i => i.IdentityValue == itemFromSet1.IdentityValue);
if (itemSet2Item != null)
{
//do stuff to create item in the persistent store
}
else
{
//do stuff to update item in the persistent store
}
}
Excusing the string comparison and parallelization considerations, is there a cheap and generic (objects may be type T, and the Identity property may be something else) way to reduce the O(n^2) nature of this?
One of solutions is to use Enumerable.Join method which have complextiy O(n)
List<Foo> itemSet1 = GenerateLargeItemSet(); //makes a large list, > 5000 items for example
List<Foo> itemSet2 = GenerateLargeItemSet();
// O(n)
var joinedSet = itemSet1.Join(itemSet2, s1 => s1.IdentityValue, s2 => s2.IdentityValue, (f1, f2) => f1).ToList();
// O(n)
foreach (var joinedItem in joinedSet)
{
//do stuff to create item in the persistent store
}
// O(n)
var unjoinedSet = itemSet1.Except(joinedSet);
// O(n)
foreach (var unjoinedItem in unjoinedSet)
{
//do stuff to update item in the persistent store
}
A well known way of improving the database queries speed is creating an index. The same principle can be applied here. But what is an index? It's just a data structure that allows fast searching. In BCL such structure is called Dictionary. So you can use something like this which will have O(N) time complexity
If the value is unique inside the set
var item2Index = itemSet2.ToDictionary(item => item.IdentityValue);
If not
var item2Index = itemSet2.GroupBy(e => e.IdentityValue)
.ToDictionary(g => g.Key, g => g.First());
and then
foreach (var itemFromSet1 in itemSet1)
{
//does a corresponding item exist in itemSet2?
Foo itemSet2Item;
if (!item2Index.TryGetValue(itemFromSet1.IdentityValue, out itemSet2Item))
{
//do stuff to create item in the persistent store
}
else
{
//do stuff to update item in the persistent store
}
}
If you want just to check for a duplicate item in the second set, but don't actually need the duplicate item, then you can use a simple HashSet (another BCL data structure for fast lookup)
var item2Keys = new HashSet<string>(itemSet2.Select(e => e.IdentityValue));
foreach (var itemFromSet1 in itemSet1)
{
//does a corresponding item exist in itemSet2?
if (!item2Keys.Contains(itemFromSet1.IdentityValue))
{
//do stuff to create item in the persistent store
}
else
{
//do stuff to update item in the persistent store
}
}
You can create Dictionary<TKey, TValue> first and then use its fast lookups it provides almost O(1) :
List<Foo> itemSet1 = GenerateLargeItemSet(); //makes a large list, > 5000 items for example
Dictionary<string, Foo> itemSet2 = GenerateLargeItemSet().ToDictionary(i => i.IdentityValue);
//O(N)
foreach (var itemFromSet1 in itemSet1)
{
//O(1)
if (!itemSet2.ContainsKey(itemFromSet1.IdentityValue))
{
//do stuff to create item in the persistent store
}
else
{
//do stuff to update item in the persistent store
}
}
You may find a performance improvement with the use of a HashSet.
List<Foo> itemSet1 = GenerateLargeItemSet(); //makes a large list, > 5000 items for example
HashSet<Foo> itemSet2 = new HashSet<Foo>(GenerateLargeItemSet());
foreach (var itemFromSet1 in itemSet1)
{
//does a corresponding item exist in itemSet2?
if (itemSet2.Contains(itemFromSet1))
{
//do stuff to update item in the persistent store
}
//do stuff to create item in the persistent store
}

Iterating over dynamically modifying list in C#

I need to iterate over a list (or whatever enumeration), but I'd like to add values into the list in the course of the iteration.
This is an example.
public static void RunSnippet()
{
List<int> hello = new List<int>();
hello.Add(1); hello.Add(2); hello.Add(3);
foreach (var x in hello)
{
Console.WriteLine(x);
if (x == 1) {
hello.Add(100);
}
}
}
I expect to get "1,2,3,100", but instead I got this error.
How can I iterate over a list that is changing in the process?
ADDED
What I want to accomplish is that I iterate over elements to process something. The thing is that some of the elements needs to be decomposed into sub elements on and on.
public static void RunSnippet()
{
List<Element> hello = new List<Element>();
hello.Add(Element); hello.Add(Element); hello.Add(Element);
foreach (var x in hello)
{
List<Element> decomposed;
decomposed = Decompose(x);
if (decomposed != null) {
foreach (var y in decomposed)
{
hello.Add(y);
}
}
}
}
You can't, basically. Not with a foreach loop, anyway. You can use a straight for loop:
for (int i = 0; i < hello.Count; i++)
{
int x = hello[i];
Console.WriteLine(x);
if (x == 1) {
hello.Add(100);
}
}
I would personally try to avoid doing it in the first place though - it can get very hard to reason about whether you'll ever complete, or if you'll skip items (if you're removing instead of adding, or adding before your current position).
You can't. You should create a new list and store the values in there.
public static void RunSnippet()
{
List<int> hello = new List<int>();
List<int> additions = new List<int>();
hello.Add(1); hello.Add(2); hello.Add(3);
foreach (var x in hello)
{
Console.WriteLine(x);
if (x == 1) {
additions.Add(100);
}
}
hello.AddRange(additions);
}
Use a snapshot of it instead:
foreach (var x in hello.ToArray())
{
// whatever here
}
Problem solved! Well, in a way. Items added during iteration would not be included.
No, you can't iterate over a list and modify them in the same iteration. Use a new list instead.
I found that there is stack in C#. I guess I could use stack.
public static void RunSnippet()
{
Stack<int> hello = new Stack<int>();
hello.Push(1); hello.Push(2); hello.Push(3);
while (hello.Count > 0)
{
int x = hello.Pop();
Console.WriteLine(x);
if (x == 1) {
hello.Push(100);
}
}
}
Using foreach you can't! You could use a for-loop, but it's very very bad style to do things like this. Things like this make your code very error prone, unpredictable and hard to debug.
There are answers that claims what you want cannot be achieved with foreach. That claim is wrong, all you need to do is to write a custom class with a custom enumerator.
public class CustomList : IEnumerable<int>
{
readonly List<int> list = new List<int>{1,2,3,4};
private int now = 0;
public void Add(int n)
{
list.Add(n);
}
public IEnumerator<int> GetEnumerator()
{
while (now<list.Count)
{
yield return list[now];
now++;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Now the following piece of code will print 1,2,3,4 and 100 to the screen:
var list = new CustomList();
foreach (int n in list)
{
if(n==1)
list.Add(100);
Console.WriteLine(n);
}
But I write this only as a proof of concept. You don't want to do this. If you will only add new items on the back, use Queue as others has said. If you will always add new items on the front, use Stack. If you will need both, write a custom LinkedList class with Dequeue (=Pop), Enqueue and Push operations, use something like :
while(list.notEmpty())
var item = list.Dequeue();
//bla bla
and you are all set. (You could even write a custom Enumerator again, to use with foreach, but we are destructing the list as we go, so it is against the spirit of Enumerations, and why bother in any case)

Categories