Reputation: 695
This is a problem I have encountered again and again in C#, but haven't found a general solution. In C++/STL, all values in a map can be updated in O(n) time using an iterator without using keys to access each element. Is there a way to obtain similar behavior with any of the C# collections such as SortedList, SortedDictionary?
I can do something like
foreach (int key in list.Keys)
{
list[key] *= 3;
}
But that would take O(n * log(n)) as the searching each element using key takes log(n).
Just to give an idea, I am looking for something along the lines of:
SortedList<int, double> list = new SortedList<int,double>();
// Add few values fist
// E.g. first try ...
IList<double> values = list.Values;
for (int i = 0; i < values.Count; i++)
{
values[i] *= 3;
}
// E.g. second try
foreach (KeyValuePair<int, double> kv in list)
{
kv.Value *= 3;
}
Since the List is already sorted it should be possible to traverse it updating values (not keys) at the same time. It doesn't look like there is a problem with that from the implementation point of view, but for some reason the functionality is not made available it seems.
Also this is not a trivial case as the same method can be used to iterate from a known position to another modifying values in that range.
Is there a way to do this in C# with any of the keyed collections in .NET without using 3rd party libraries?
Thank you
Jeeves
Upvotes: 6
Views: 974
Reputation: 9533
SortedList<int, double> list = new SortedList<int,double>
{
{ 1, 3.14 },
{ 2, 1.618 },
};
var newList = new SortedList<int, double>(list.ToDictionary(kv => kv.Key, kv => kv.Value * 3)).Dump();
The SortedList constructor is O(n) according to the docs.
The .ToDictionary loops over Dictionary.Add under the hood. Dictionary.Add is O(1) when the capacity is sufficient source
O(n) * O(1) is still O(n) so you're good :-)
The space requirements are of course doubled using this approach.
Upvotes: 2
Reputation: 40345
In C# accessing a Dictionary element is close to constant time of O(1).
You can get a list of values by calling Dictionary.Values and updating them:
foreach(var value in valuesDict.Values)
{
// update value;
}
Getting the value of this property (Dictionary.Values
) is also an O(1) operation..
Upvotes: 0
Reputation: 21485
Simplest solution would be to wrap the value in a reference type.
class WrappedInt { public int Value; }
Dictionary<TKey, WrappedInt> dictionary = ...;
foreach (var wrappedVal in dictionary.Values)
{
wrappedVal.Value *= 3;
}
// or
foreach (var wrappedVal in dictionary)
{
wrappedVal.Value.Value *= 3;
}
This approach would work with any collection (list or dictionary). One of the few collections that does this by design without the wrapper is LinkedList
.
Of course, if you have a very specific collection (created by some external component), you can always fall back to using reflection and change the values directly in the underlying storage.
Upvotes: 3