This question already has answers here:
Why does adding a new value to list<> overwrite previous values in the list<>
(2 answers)
Closed 4 years ago.
I have a code block similar to this:
List<Object> returnObjDataLine = new List<object>();
foreach (var tuple in dataPerTime)
{
returnObjDataLine.Clear();
returnObjDataLine.Add(tuple.Item1);
foreach (var line in PlotLines)
{
if (tuple.Item2.Equals(line.Key))
{
returnObjDataLine.Add(tuple.Item3);
}
else
{
returnObjDataLine.Add(null);
}
}
returnObjData.Add(returnObjDataLine);
}
However the Clear() method clears out the data already added to the returnObjData Dictionary, sort of. If there are 10,000 tuples, then after the loop runs the returnObjData will contain 10,000 instances of the very last data piece added (Clear() is not called after the last iteration).
If I modify the code to create a new List each iteration:
foreach (var tuple in dataPerTime)
{
List<Object> returnObjDataLine = new List<object>();
returnObjDataLine.Add(tuple.Item1);
foreach (var line in PlotLines)
{
if (tuple.Item2.Equals(line.Key))
{
returnObjDataLine.Add(tuple.Item3);
}
else
{
returnObjDataLine.Add(null);
}
}
returnObjData.Add(returnObjDataLine);
}
the loading loop works correctly but this seems very expensive as there can be 10s if not 100s of thousands of iterations required. Creating a new object every time seems to be inefficient.
What am I missing with Clear()? Is there some sort of "commit" that needs to be called first?
Looks like what you need to do is have a temporary list and a long term list... Something like this:
List<Object> longTermObjects = new List<object>();
foreach (var tuple in dataPerTime)
{
List<Object> returnObjDataLine = new List<Object>();
returnObjDataLine.Add(tuple.Item1);
foreach (var line in PlotLines)
{
if (tuple.Item2.Equals(line.Key))
{
returnObjDataLine.Add(tuple.Item3);
}
else
{
returnObjDataLine.Add(null);
}
}
longTermObjects.Add(returnObjDataLine);
}
This will give you a clean returnObjDataLine each iteration without removing the referenced items in longTermObjects.
Edit To Add Reference Type Information:
By default .NET will store 1 copy of an object into memory, and then "reference" that object anywhere you use it. Take the following example:
int A = 1;
int B = A;
Console.WriteLine($"A = {A}");
Console.WriteLine($"B = {B}");
A = 0;
Console.WriteLine($"A = {A}");
Console.WriteLine($"B = {B}");
Result:
A = 1
B = 1
A = 0
B = 0
Why you ask does B = 0 on the 4th line? Because B had a REFERENCE to A, it didn't contain the actual VALUE of A, so when A changed, B changed as well.
If I wanted B to contain only the value of A then I would need a way to create a new "value" instead of a reference. The way you do this varies for each type of object. One way and probably not the best would be something like:
int B = int.Parse(A.ToString());
Which would convert A to a string representing the value of A and then into a new int with the Parse. Now I have the value stored in B instead of just a reference.
If I wanted to do the same thing with a table of objects then I would have to do something like this:
List<MyObject> oldList = new List<MyObject>();
//Put some objects into oldList
List<MyObject> newList = oldList.Select(x => new MyObject(x.Param1, x.Param2)).ToList();
In this example I am basically taking each object in oldList and creating a new MyObject which is then put into newList.
Related
How can I execute a method one by one in the order they were added to the List<Action>?
List<Action> actions = new List<Action>();
List<int> listaInt = new List<int>();
for (int i = 0; i < 5; i++) {
listaInt.Add(i);
var entries = entries1.Select(d => string.Format("{0}", string.Join(",", d)));
actions.Add(new Action(() => {
Console.WriteLine("counterList: " + string.Join(",", entries ));
}));
}
I want to execute every function, but with the list of integers(List<int>)
foreach (Action action in actions) {
action();
}
Result:
listaInt: 0,1,2,3,4
listaInt: 0,1,2,3,4
listaInt: 0,1,2,3,4
listaInt: 0,1,2,3,4
listaInt: 0,1,2,3,4
Expected result:
listaInt: 0
listaInt: 0,1
listaInt: 0,1,2
listaInt: 0,1,2,3
listaInt: 0,1,2,3,4
Your question isn't entirely clear. But it seems like what you want is for each element (i.e. "snapshot") in the list to represent the original List<int>'s state at the time it was added to the action list.
If so, then the main problem here is that you are adding the reference to the original list. Any changes to that list later will still be observed in any copy of that reference, such as those you are adding.
If you want an actual "snapshot", then you need to make one. I.e. make a copy of the list when you add it to the action list. For example:
public static void TakeSnapShot(List<int> listaInt, int i) {
GridSnapshotAction gridSnapshotAction = new GridSnapshotAction();
List<int> listCopy = new List<int>(listaInt);
gridSnapshotAction.AddAction(() => {
Console.WriteLine(i);
PrintLista(listCopy);
});
gridSnapshotActionList.Add(gridSnapshotAction);
}
There are other places in the code where you might make a copy. And there are other ways you could implement this. For example, if you were using ImmutableList<T>, then the original list reference would be the one getting updated, while each captured list would be the snapshot you want (and this approach would be somewhat more efficient, since ImmutableList<T> is optimized to share data between copies of the list when possible).
The bottom line is: if you want separate copies of the list object, you need to do something to make sure you have separate copies. Reference types like List<T> don't copy the contents of the object when you assign the reference; just the reference itself is copied, all copies of that reference will refer to the same object, and changes to that one object will be observed when using any copy of that reference.
If I understand your question correctly, the problem is by the time the actions are executed the list already contains 5 elements, therefore they will all print 5 items. If what you want is to print the items that were contained when the action was added to actions, then you can create the string with the desired output and then print that string. Because that string is in the closure, you'll be able to access it with the value you expect, i.e.
public static void PrintList()
{
var actions = new List<Action>();
var listaInt = new List<int>();
for (int i = 0; i < 5; i++)
{
listaInt.Add(i);
var entries = string.Join(",", listaInt.Select(d => string.Format("{0}", string.Join(",", d))));
actions.Add(() => Console.WriteLine("counterList: " + entries));
}
foreach (var action in actions)
{
action();
}
}
i'm using two list as methods paremeters on a controller but right now i'm getting a problem... Per example, i have the first list with three objects and the second list with three objects too. Right know i just want to get per each object from the first list the corresponding object from the second list.. like [0]-[0];[1]-[1];[2]-[2]...
I use two foreach to iterate each list but the problem cames when after i go to the second object from Turno list because after that when i start the iteration of DocenteId List the iteration starts at the [0] object but in the reality i don't want the first object of DocenteId list again but the second...
The if clause that i have is just because i cannot repeat the TurnoId value that cames with the Turno list object... The real thing happens when the DocenteId list cames with same values like object[0]-1;object[1]-1;object[1]-2; I want this to happen but i just want to get three values as result on the turnodocente List so here is the problem i just can switch the Turno object but not the DocenteId object... What happens with my method right now is that the result came with three values but foreach Turno object i get always the first object value for DocenteId list and i don't want that....
Exists some way to get this?
I will apreciate your help...
Controller method
foreach (var item in Turno)
{
foreach (var ite in DocenteId)
{
if (!turnodocente.Any(x =>x.TurnoId == item.TurnoId))
{
turnodocente.Add(new TurnoDocente
{
TurnoId = item.TurnoId,
DocenteId = ite
});
}
}
}
I don't know if i fully understand your problem but, if both lists have the same number of objects, i think the solution could be like:
for(int i=0; i<Turno.Count(); i++)
{
turnodocente.Add(new TurnoDocente
{
TurnoId = Turno[i],
DocenteId = DocenteId[i]
});
}
Let me know if it helps you.
EDIT: I just tought it might be good to explain. When you use foreach in another foreach, the iteration of indexes looks like this:
0 - 0, 0 - 1, 0 - 2... 1 - 0, 1 - 1, 1 - 2... etc so basicaly there is a * a iterations. What you need is just one iteration through both lists, so "for" loop is a good option because you will get objects from both lists that are at the same index. I hope it's clrear :)
Considering you have the same number of objects in both lists;
var Turno = new List<int>() {1000, 2000, 3000};
var DocenteId = new List<int> {5000, 6000, 7000};
var turnodocente = new List<KeyValuePair<int, int>>();
for (int i = 0; i < Turno.Count; i++)
{
if (turnodocente.All(x => x.Key != Turno[i]))
{
turnodocente.Add(new KeyValuePair<int, int>(Turno[i], DocenteId[i]));
Console.WriteLine(turnodocente[i].Key +" " + turnodocente[i].Value);
}
}
Sounds like you might need Enumerable.Zip
List<int> turno = new List<int>() {1, 2, 3};
List<string> docenteId = new List<string> {"foo", "bar", "doe"};
IEnumerable<TurnoDocente> turnodocente = turno.Zip(docenteId, (x, y) => new TurnoDocente() {TurnoId = x, DocenteId = y} );
I have two key-value pairs, and now I want to fill up the larger one with values from the smaller one in a serial manner.
OrderedDictionary pickersPool = new OrderedDictionary(); // Small
OrderedDictionary pickersToTicketMap = new OrderedDictionary(); // Big
pickersPool.Add("emp1", 44);
pickersPool.Add("emp2", 543);
Now I need to update pickersToTicketMap to look like this:
("100", 44);
("109", 543);
("13", 44);
("23", 543);
So basically I need the pickersPool value to cycle through the keys of the pickersToTicketMap dictionary.
I need pickerPool values to keep cycling pickersToTicketMap and updating its value serially.
The pickersToTicketMap orderedlist initially has a value of:
("100", "null");
("109", "null");
("13", "null");
("23", "null");
so I need for the values of PickerPool orderedDictionary to fill up those nulls in a repeated fashion.
It sounds like you should start with a List<string> (or possibly a List<int>, given that they all seem to be integers...) rather than populating your map with empty entries to start with. So something like:
List<string> tickets = new List<string> { "100", "109", "13", "23" };
Then you can populate your pickersToTicketMap as:
var pickers = pickersPool.Values;
var pickerIterator = pickers.GetEnumerator();
foreach (var ticket in tickets)
{
if (!pickerIterator.MoveNext())
{
// Start the next picker...
pickerIterator = pickers.GetEnumerator();
if (!pickerIterator.MoveNext())
{
throw new InvalidOperationException("No pickers available!");
}
}
ticketToPickerMap[ticket] = pickerIterator.Current;
}
Note that I've changed the name from pickersToTicketMap to ticketToPickerMap because that appears to be what you really mean - the key is the ticket, and the value is the picker.
Also note that I'm not disposing of the iterator from pickers. That's generally a bad idea, but in this case I'm assuming that the iterator returned by OrderedDictionary.Values.GetEnumerator() doesn't need disposal.
There may be what you are looking for:
using System.Linq;
...
int i = 0;
// Cast OrderedDictionary to IEnumarable<DictionaryEntry> to be able to use System.Linq
object[] keys = pickersToTicketMap.Cast<DictionaryEntry>().Select(x=>x.Key).ToArray();
IEnumerable<DictionaryEntry> pickersPoolEnumerable = pickersPool.Cast<DictionaryEntry>();
// iterate over all keys (sorted)
foreach (object key in keys)
{
// Set the value of key to element i % pickerPool.Count
// i % pickerPool.Count will return for Count = 2
// 0, 1, 0, 1, 0, ...
pickersToTicketMap[key] = pickersPoolEnumarable
.ElementAt(i % pickersPool.Count).Value;
i++;
}
PS: The ToArray() is required to have a separate copy of the keys, so you don't get a InvalidOperationException due to changing the element you are iterating over.
So you want to update the large dictionary's values with consecutive and repeating values from the possibly smaller one? I have two approaches in mind, one simpler:
You can repeat the smaller collection with Enumerable.Repeat. You have to calculate the count. Then you can use SelectMany to flatten it and ToList to create a collection. Then you can use a for loop to update the larger dictionary with the values in the list via an index:
IEnumerable<int> values = pickersPool.Values.Cast<int>();
if (pickersPool.Count < pickersToTicketMap.Count)
{
// Repeat this collection until it has the same size as the larger collection
values = Enumerable.Repeat( values,
pickersToTicketMap.Count / pickersPool.Count
+ pickersToTicketMap.Count % pickersPool.Count
)
.SelectMany(intColl => intColl);
}
List<int> valueList = values.ToList();
for (int i = 0; i < valueList.Count; i++)
pickersToTicketMap[i] = valueList[i];
I would prefer the above approach, because it's more readable than my second which uses an "infinite" sequence. This is the extension method:
public static IEnumerable<T> RepeatEndless<T>(this IEnumerable<T> sequence)
{
while (true)
foreach (var item in sequence)
yield return item;
}
Now you can use this code to update the larger dictionary's values:
var endlessPickersPool = pickersPool.Cast<DictionaryEntry>().RepeatEndless();
IEnumerator<DictionaryEntry> endlessEnumerator;
IEnumerator<string> ptmKeyEnumerator;
using ((endlessEnumerator = endlessPickersPool.GetEnumerator()) as IDisposable)
using ((ptmKeyEnumerator = pickersToTicketMap.Keys.Cast<string>().ToList().GetEnumerator()) as IDisposable)
{
while (endlessEnumerator.MoveNext() && ptmKeyEnumerator.MoveNext())
{
DictionaryEntry pickersPoolItem = (DictionaryEntry)endlessEnumerator.Current;
pickersToTicketMap[ptmKeyEnumerator.Current] = pickersPoolItem.Value;
}
}
Note that it's important that I use largerDict.Keys.Cast<string>().ToList(), because I can't use the original Keys collection. You get an exception if you change it during enumeration.
Thanks to #jon skeet, although he modified my objects too much while trying to provide a hack for this.
After looking at your solution, I implemented the following, which works well for all my objects.
var pickerIterator = pickerPool.GetEnumerator();
foreach (DictionaryEntry ticket in tickets)
{
if (!pickerIterator.MoveNext())
{
// Start the next picker...
pickerIterator = pickerPool.GetEnumerator();
if (!pickerIterator.MoveNext())
{
throw new InvalidOperationException("No pickers available!");
}
}
ticketToPickerMap[ticket.Key] = pickerIterator.Value.ToString();
}
Is there a way to access the objects in the list? like, getting an exact field in a particular object. For Instance:
List<Object> allObjectResult = new List<Object>();
allObjectResult.AddRange(method(ObjectOne.ToArray()));
allObjectResult.AddRange(method(ObjectTwo.ToArray()));
allObjectResult.AddRange(method(ObjectThree.ToArray()));
I want to get a particular field in ObjectOne, ObjectTwo and ObjectThree. How am I able to do that?
Updated Question
In List we can access elements position by order. My first attempt in getting the a particular value in an object inside a List works. This is what I did:
Create a new instance of a list:
List<Object> objList = new List<Object>();
Added data on it:
objList.Add(objdata);
Use it in a method:
Object[] result = binding.method(Object.ToArray());
Loop through:
for(i = 0; i < result.Length; i++)
{
Console.WriteLine("objs {0} - {1}", objList[i].Name, result[i].id);
}
However, What I want is I have three objects. What I did is added them in a List:
List<Object> allObjectResult = new List<Object>();
allObjectResult.AddRange(binding.method(ObjectOneList.ToArray()));
allObjectResult.AddRange(binding.method(ObjectTwoList.ToArray()));
allObjectResult.AddRange(binding.method(ObjectThreeList.ToArray()));
I want to do the same thing like what I did in getting a name in an object (anyway, it's an object within a List). I want them to access using a loop.
Select objects of a certain type:
foreach (var obj1 in allObjectResult.OfType<ObjectOne>()) {
Console.WriteLine(obj1.Whatever);
}
Check the type dynamically:
foreach (var obj in allObjectResult) {
if (obj is ObjectOne) {
var obj1 = (ObjectOne)obj;
Console.WriteLine(obj1.Whatever);
} // else ...
}
I have an Item object with a property called generator_list (hashset of strings). I have 8000 objects, and for each object, I'd like to see how it's generator_list intersects with every other generator_list, and then I'd like to store the intersection number in a List<int>, which will have 8000 elements, logically.
The process takes about 8 minutes, but only a few minutes with parallel processing, but I don't think I'm doing the parallel part right, hence the question. Can anyone please tell me if and how I need to modify my code to take advantage of the parallel loops?
The code for my Item object is:
public class Item
{
public int index { get; set; }
public HashSet<string> generator_list = new HashSet<string>();
}
I stored all my Item objects in a List<Item> items (8000 elements). I created a method that takes in items (the list I want to compare) and 1 Item (what I want to compare to), and it's like this:
public void Relatedness2(List<Item> compare, Item compare_to)
{
int compare_to_length = compare_to.generator_list.Count;
foreach (Item block in compare)
{
int block_length = block.generator_list.Count;
int both = 0; //this counts the intersection number
if (compare_to_length < block_length) //to make sure I'm looping
//over the smaller set
{
foreach (string word in compare_to.generator_list)
{
if (block.generator_list.Contains(word))
{
both = both + 1;
}
}
}
else
{
foreach (string word in block.generator_list)
{
if (compare_to.generator_list.Contains(word))
{
both = both + 1;
}
}
}
// I'd like to store the intersection number, both,
// somewhere so I can effectively use parallel loops
}
}
And finally, my Parallel forloop is:
Parallel.ForEach(items, (kk, state, index) => Relatedness2(items, kk));
Any suggestions?
Maybe something like this
public Dictionary<int, int> Relatedness2(IList<Item> compare, Item compare_to)
{
int compare_to_length = compare_to.generator_list.Count;
var intersectionData = new Dictionary<int, int>();
foreach (Item block in compare)
{
int block_length = block.generator_list.Count;
int both = 0;
if (compare_to_length < block_length)
{
foreach (string word in compare_to.generator_list)
{
if (block.generator_list.Contains(word))
{
both = both + 1;
}
}
}
else
{
foreach (string word in block.generator_list)
{
if (compare_to.generator_list.Contains(word))
{
both = both + 1;
}
}
}
intersectionData[block.index] = both;
}
return intersectionData;
}
And
List<Item> items = new List<Item>(8000);
//add to list
var dictionary = new ConcurrentDictionary<int, Dictionary<int, int>>();//thread-safe dictionary
var readOnlyItems = items.AsReadOnly();// if you sure you wouldn't modify collection, feel free use items directly
Parallel.ForEach(readOnlyItems, item =>
{
dictionary[item.index] = Relatedness2(readOnlyItems, item);
});
I assumed that index unique.
i used a dictionaries, but you may want to use your own classes
in my example you can access data in following manner
var intesectiondata = dictionary[1]//dictionary of intersection for item with index 1
var countOfintersectionItemIndex1AndItemIndex3 = dictionary[1][3]
var countOfintersectionItemIndex3AndItemIndex7 = dictionary[3][7]
don't forget about possibility dictionary[i] == null
Thread safe collections is probably what you are looking for http://msdn.microsoft.com/en-us/library/dd997305(v=vs.110).aspx.
When working in multithreaded environment, you need to make sure that
you are not manipulating shared data at the same time without
synchronizing access.
the .NET Framework offers some collection classes that are created
specifically for use in concurrent environments, which is what you
have when you're using multithreading. These collections are
thread-safe, which means that they internally use synchronization to
make sure that they can be accessed by multiple threads at the same
time.
Source: Programming in C# Exam Ref 70-483, Objective 1.1: Implement multhitreading and asynchronous processing, Using Concurrent collections
Which are the following collections
BlockingCollection<T>
ConcurrentBag<T>
ConcurrentDictionary<T>
ConcurentQueue<T>
ConcurentStack<T>
If your Item's index is contiguous and starts at 0, you don't need the Item class at all. Just use a List< HashSet< < string>>, it'll take care of indexes for you. This solution finds the intersect count between 1 item and the others in a parallel LINQ. It then takes that and runs it on all items of your collection in another parallel LINQ. Like so
var items = new List<HashSet<string>>
{
new HashSet<string> {"1", "2"},
new HashSet<string> {"2", "3"},
new HashSet<string> {"3", "4"},
new HashSet<string>{"1", "4"}
};
var intersects = items.AsParallel().Select( //Outer loop to run on all items
item => items.AsParallel().Select( //Inner loop to calculate intersects
item2 => item.Intersect(item2).Count())
//This ToList will create a single List<int>
//with the intersects for that item
.ToList()
//This ToList will create the final List<List<int>>
//that contains all intersects.
).ToList();