I have following code to remove group from collection. Technically, there should be no duplicates, but it does remove all anyway. Any trick with LINQ to .Remove.Where.. ?
public void DeleteGroup(KeyValuePair<int, string> group)
{
while (this.Groups.Any(g => g.Key.Equals(group.Key)))
{
var groupToRemove = this.Groups.First(g => g.Key.Equals(group.Key));
this.Groups.Remove(groupToRemove);
}
}
Assuming you are passing in a KeyValuePair with the same Key and the same Value this is the most efficient way possible with an ObseravableCollection.
public void DeleteGroup2(KeyValuePair<int, string> group)
{
Groups.Remove(group);
}
This works because a KeyValuePair is a structure and when the overloaded operator == is applied it is comparing both the Key and the Value data members of the structure.
Again this will work just fine if you pass in the exact same Key and Value that is contained in the Groups obserabableCollection...if the Value does not match it will not work.
Behind the scenes an ObserableCollection is pretty much a list so it will have to iterate over every item performing the == operator. The same is true for the code you are posting. Just because it is using LINQ doesn't mean it's any more efficient. It's not like the LINQ where clause is using any indexing like it would be with LINQ to SQL.
public void DeleteGroup3(KeyValuePair<int, string> groupToDelete)
{
var itemsToDelete =
(
from g in Groups
where g.Key == groupToDelete.Key
select g
);
foreach (var kv in itemsToDelete)
{
Groups.Remove(kv);
}
}
This would probably be most efficient method using linq if you want to guarantee that you remove all items even those with duplicate keys.
public void DeleteGroup4(KeyValuePair<int, string> group)
{
List<int> keyIndexes = new List<int>();
int maxIndex = Groups.Count;
for (int i = 0; i < maxIndex; i++)
{
if (Groups[i].Key == group.Key)
{
keyIndexes.Add(i);
}
}
int indexOffset = 0;
foreach (int index in keyIndexes)
{
Groups.RemoveAt(index - indexOffset);
indexOffset++;
}
}
This should have the best performance of all of them if you have multiple items with the same key or you don't know the exact same Key Value pair as the original.
I believe your DeleteGroup method is BIG O of 2N^2...N for the outer Any while Loop and N for the First and N for the Remove. Take outer Loop times the sum of the inside and you get 2N^2
DeleteGroup2 is BIG O of N and had the best performance of all of them. The drawback is that you need to know both the Key and the Value not just the Key. It will also only remove the first item it finds. It won't delete duplicate items with the same Key and the same Value.
DeleteGroup3 IS BIG O of N + N^2. N for the select. Worse case is that your key is in there N times so N^2 for the removal.
DeleteGroup4 is BIG O of 2N. N to find the indexes and in worst case if you have all items with the same key then its N to remove each of them as RemoveAtIndex is a Big O of 1. This has the best performance if you only know the Key and you have the possibility of having multiple items with the same Key.
If you know for a fact that you won't have duplicate items I would use DeleteGroup2. If you have the possibility of having duplicates DeleteGroup4 should have the best performance.
On a side note if won't have duplicates and you don't necessarily know both the Key and the Value you can still use the best performing option of DeleteGroup2 but create a class called KeyValueIntString with properties of Key and Value. Then overide the IsEquals method so that it only compares the Key property unlike the KeyValue struct that compares both the Key and the Value data members. Then you can use the ObserableCollection.Remove method and not have to worry about knowing the value that is stored. I.E. you could pass in instance of a KeyValueIntString that has the Key set but you don't have to worry about setting the Value property.
After commenting I decided to Add best readability method although it does have worse performance. Has a Big O of N^4. N for select, N for ToList, N for ForEach and N for Remove.
public void DeleteGroup5(KeyValuePair<int, string> groupToDelete)
{
(
from g in Groups
where g.Key == groupToDelete.Key
select g
).ToList().ForEach(g => Groups.Remove(g));
}
Related
I have a list contains duplicate items.
List<string> filterList = new List<string>()
{
"postpone", "access", "success", "postpone", "success"
};
I get the output which is postpone, access, success by using
List<string> filter = filterList.Distinct().ToList();
string a = string.Join(",", filter.Select(a => a).ToArray());
Console.WriteLine(a);
I had saw other example, they can use groupby to get the latest element since they have other item like ID etc. Now I only have the string, how can I get the latest item in the list which is access, postpone, success? Any suggestion?
One way to do this would be use the Index of the item in original collection along with GroupBy. For example,
var lastDistinct = filterList.Select((x,index)=> new {Value=x,Index=index})
.GroupBy(x=>x.Value)
.Select(x=> x.Last())
.OrderBy(x=>x.Index)
.Select(x=>x.Value);
var result = string.Join(",",lastDistinct);
Output
access,postpone,success
An OrderedDictionary does this. All you have to do is add your items to it with a logic of "if it's in the dictionary, remove it. add it". OrderedDictionary preserves the order of adding so by removing an earlier added one and re-adding it it jumps to the end of the dictionary
var d = new OrderedDictionary();
filterList.ForEach(x => { if(d.Contains(x)) d.Remove(x); d[x] = null; });
Your d.Keys is now a list of strings
access
postpone
success
OrderedDictionary is in the Collections.Specialized namespace
If you wanted the keys as a CSV, you can use Cast to turn them from object to string
var s = string.Join(",", d.Keys.Cast<string>());
Your input list is only of type string, so using groupBy doesn't really add anything. If you consider your code, your first line gives you the distinct list, you only lose the distinct items because you did a string.join on line 2. All you need to do is add a line before you join:
List<string> filter = filterList.Distinct().ToList();
string last = filter.LastOrDefault();
string a = string.Join(",", filter.Select(a => a).ToArray());
Console.WriteLine(a);
I suppose you could make your code more terse because you need neither .Select(a => a) nor .ToArray() in your call to string.Join.
GroupBy would be used if you had a list of class/struct/record/tuple items, where you might want to group by a specific key (or keys) rather than using Distinct() on the whole thing. GroupBy is very useful and you should learn that, and also the ToDictionary and ToLookup LINQ helper functionality.
So why shouldn't you return the first occurrence of "postpone"? Because later in the sequence you see the same word "postpone" again. Why would you return the first occurrence of "access"? Because later in the sequence you don't see this word anymore.
So: return a word if the rest of the sequence does not have this word.
This would be easy in LINQ, with recursion, but it is not very efficient: for every word you would have to check the rest of the sequence to see if the word is in the rest.
It would be way more efficient to remember the highest index on which you found a word.
As an extension method. If you are not familiar with extension methods, see extension methods demystified.
private static IEnumerable<T> FindLastOccurences<T>(this IEnumerable<T> source)
{
return FindLastOccurrences<T>(source, null);
}
private static IEnumerable<T> FindLastOccurences<T>(this IEnumerable<T> source,
IEqualityComparer<T> comparer)
{
// TODO: check source not null
if (comparer == null) comparer = EqualityComparer<T>.Default;
Dictionary<T, int> dictionary = new Dictionary<T, int>(comparer);
int index = 0;
foreach (T item in source)
{
// did we already see this T? = is this in the dictionary
if (dictionary.TryGetValue(item, out int highestIndex))
{
// we already saw it at index highestIndex.
dictionary[item] = index;
}
else
{
// it is not in the dictionary, we never saw this item.
dictionary.Add(item, index);
}
++index;
}
// return the keys after sorting by value (which contains the highest index)
return dictionay.OrderBy(keyValuePair => keyValuePair.Value)
.Select(keyValuePair => keyValuePair.Key);
}
So for every item in the source sequence, we check if it is in the dictionary. If not, we add the item as key to the dictionary. The value is the index.
If it is already in the dictionary, then the value was the highest index of where we found this item before. Apparently the current index is higher, so we replace the value in the dictionary.
Finally we order the key value pairs in the dictionary by ascending value, and return only the keys.
I'm currently working on a project where I have to loop over a dictionary. I only want to loop over the keys in this dictionary which contain a substring of a. So for a dictionary (key, value) I only want to loop through the pairs in this dictionary for which the key contains A.
How would I do this?
How would I do this?
Dictionaries only offer O(1) (fast) access when checking for equality. There's not a way to "select" keys that contain a value without looping:
foreach(var entry in myDictionary)
{
if(entry.Key.Contains("A"))
// do something with entry.Value
}
You could use the Where method from Linq but it doesn't offer any performance improvement (it still loops internally):
foreach(var entry in myDictionary.Where(e => e.Key.Contains("A"))
{
// do something with entry.Value
}
Lots of ways. Here is one example (not tested).
var keys = dictionary.Keys.Where(k => k.Contains(a));
foreach (var matchingKey in keys)
{
var value = dictionary[matchingKey];
// Do something
}
I currently have a dictionary with an int key and the value is an instance of a class called MachinePart.
The key is significant to the what type of machine part the MachinePart is. For example, if the key is between 0-99 the machine part is in a category called "Free Movement". If the key is between 100-199,the machine part is in another category and so on...
Therefore it is useful to have a method which will retrieve a certain category from the dictionary. To clarify to return a list of Machine Parts who keys are within a certain range.
Below is the code I currently have to retrieve the free movement parts. It works fine however I was wondering if there was a more improved way of writing this instead of having to have a loop which iterates 99 times.
public static List<MachinePart> getFreeMovementParts(Dictionary<int, MachinePart> iMachineParts)
{
List<MachinePart> temp = new List<MachinePart>();
for (int i = 0; i < 99; i++)
{
MachinePart t;
if (iMachineParts.TryGetValue(i, out t))
{
temp.Add(t);
}
}
return temp;
}
You could use Linq to select the values as follows:
var freeMovementParts = iMachineParts.Where(it => it.Key >= 0 && it.Key <= 99)
.Select(it => it.Value)
.ToList();
But as suggested in the comments, it's better to think of an alternative data structure for the implementation. Also it is worth noting that iterating over the keys will lead to poor performance if the dictionary contains large number of items and you will lose the perf benefits of using the dictionary.
If you'd like to Linq-ify your code you can do something like this:
public static List<MachinePart> getFreeMovementParts(Dictionary<int, MachinePart> iMachineParts)
{
return Enumerable.Range(0, 99)
.Select(i => { iMachineParts.TryGetValue(i, out var mp); return mp; })
.Where(mp => mp != null)
.ToList();
}
It does not solve problems mentioned in the comments, a different data structure might still be more appropriate, the above is mostly just for fun.
Performance of this approach vs performance of the "enumerate all keys" approach - it is similar to DB indexes, on a small data set it is often cheaper to do a full scan (enumerate all keys). But when you need only a small subset of items from a large dictionary - it will be cheaper to do the item lookups based on known range of keys.
var r = from part in iMachineParts
where part.Key >= 0 && part.Key <= 99
select part.Value;
return r.ToList();
I have a dictionary where the key is defined by a Vector2, and I am trying to perform a function involving keys of matching Y-values. (Building a graph)
Right now I am using two foreach loops, one to go through each entry and the second to find keys of matching criteria.
foreach(KeyValuePair<Vector2, TransportData> entry in transportDictionary)
//for every value in dictionary
{
Vector2 forpos = entry.Key;
foreach(KeyValuePair<Vector2, TransportData> searchEntry in transportDictionary)
//go through every value in dictionary
{
if(searchEntry.Key.y == forpos.y && searchEntry.Key.x != forpos.x)
//if something is found with matching Y value, at a different X value as to not include itself
{
DoSomething(forpos, searchEntry.key);
//pass the two matched values as arguments
}
}
DoSomethingElse(forpos); //(functions need to be run on every entry individually too)
}
It works, but it is horribly efficient, and I forsee this dictionary having over a thousand entries. With a small test set of 50 entries, this operation is already taking an unacceptably long time.
How can I optimize this operation? (or am I doing something fundamentally wrong?)
If it helps with finding a method, the x and y coordinates of every Vector2 in this application will always be an integer.
--edit--
I need to run a function on every entry anyway, so it isn't necessary to subset the starting dictionary.
One idea would be to first filter your transportDictionary down to only those items that have at least one matching Key.Y, and then just deal with a list of keys (since that's all you seem to need).
Then you could also change the second foreach to only compare to keys that have a Y match, so you aren't looping through all of the keys in each loop:
Finally, you could also remove all the items you've just processed as you go, so you aren't iterating over them multiple times (of course, I don't know what DoSomething() does...if you need to iterate over matches more than once then this wouldn't work):
List<Vector2> allKeysThatHaveAMatch = transportDictionary.Where(current =>
transportDictionary.Count(other => current.Key.Y == other.Key.Y) > 1)
.Select(item => item.Key)
.ToList();
while (allKeysThatHaveAMatch.Any())
{
// Get the first key
var currentKey = allKeysThatHaveAMatch.First();
// Get all matching keys
var matchingKeys = allKeysThatHaveAMatch
.Skip(1)
.Where(candidateKey => candidateKey.Y == currentKey.Y)
.Select(match => match)
.ToList();
// Do Something with each match
foreach (var matchingKey in matchingKeys)
{
DoSomething(currentKey, matchingKey);
}
// Remove the key we just processed
allKeysThatHaveAMatch.Remove(currentKey);
}
I have a hash table that contains values of a^j. j is the key and a^j is the value.
I am now calculating another value a^m. I basically want to see if a^m is in the hash table.
I used the ContainsValue fn. to find the value. How would i go about finding out the key of the value?
Here is a little snippet of where i want to implement the search for the value.
Dictionary<BigInteger, BigInteger> b = new Dictionary<BigInteger, BigInteger>();
***add a bunch of BigIntegers into b***
for(int j=0; j < n; j++)
{
z = q* BigInteger.ModPow(temp,j,mod);
***I want to implement to search for z in b here****
}
Does this change anything? the fact that i am searching while inside a for loop?
The fastest way is probably to iterate through the hashtable's DictionaryEntry items to find the value, which in turn gives you the key. I don't see how else to do it.
Firstly, you should absolutely be using Dictionary<TKey, TValue> instead of Hashtable - if you're using BigInteger from .NET 4, there's no reason not to use generic collections everywhere you can. Chances are for the most part you'd see no difference in how it's used - just create it with:
Dictionary<BigInteger, BigInteger> map =
new Dictionary<BigInteger, BigInteger>();
to start with. One thing to watch out for is that the indexer will throw an exception if the key isn't present in the map - use TryGetValue to fetch the value if it exists and a bool to say whether or not it did exist.
As for finding the key by value - there's no way to do that efficiently from a Dictionary. You can search all the entries, which is most easily done with LINQ:
var key = map.Where(pair => pair.Value == value)
.Select(pair => pair.Key)
.First();
but that will iterate over the whole dictionary until it finds a match, so it's an O(n) operation.
If you want to do this efficiently, you should keep two dictionaries - one from a to a^j and one from a^j to a. When you add an entry, add it both ways round. Somewhere on Stack Overflow I've got some sample code of a class which does this for you, but I doubt I'd be able to find it easily. EDIT: There's one which copes with multiple mappings here; the "single mapping" version is in the answer beneath that one.
Anyway, once you've got two dictionaries, one in each direction, it's easy - obviously you'd just lookup a^m as a key in the second dictionary to find the original value which created it.
Note that you'll need to consider whether it's possible for two original keys to end up with the same value - at that point you obviously wouldn't be able to have both mappings in one reverse dictionary (unless it was a Dictionary<BigInteger, List<BigInteger>> or something similar).
Edit: Changed to use Dictionary<TKey, TValue>
Dictionary<TKey, TValue> is an IEnumerable<KeyValuePair<TKey, TValue>>. If you do a foreach over it directly, you can get both the key and value for each entry.
class SomeType
{
public int SomeData = 5;
public override string ToString()
{
return SomeData.ToString();
}
}
// ...
var blah = new Dictionary<string, SomeType>();
blah.Add("test", new SomeType() { SomeData = 6 });
foreach (KeyValuePair<string, SomeType> item in blah)
{
if(e.Value.SomeData == 6)
{
Console.WriteLine("Key: {0}, Value: {1}", item.Key, item.Value);
}
}
If you have a newer version of the .Net framework, you could use Linq to find your matches, and place them in their own collection. Here's a code sample showing a little bit of Linq syntax:
using System;
using System.Collections;
using System.Linq;
class SomeType
{
public int SomeData = 5;
public override string ToString()
{
return SomeData.ToString();
}
}
class Program
{
static void Main(string[] args)
{
var blah = new Dictionary<string, SomeType>();
blah.Add("test", new SomeType() { SomeData = 6 });
// Build an enumeration of just matches:
var entriesThatMatchValue = blah
.Where(e => e.Value.SomeData == 6);
foreach (KeyValuePair<string, SomeType> item in entriesThatMatchValue)
{
Console.WriteLine("Key: {0}, Value: {1}", item.Key, item.Value);
}
// or: ...
// Build a sub-enumeration of just keys from matches:
var keysThatMatchValue = entriesThatMatchValue.Select(e => e.Key);
// Build a list of keys from matches in-line, using method chaining:
List<string> matchingKeys = blah
.Where(e => e.Value.SomeData == 6)
.Select(e => e.Key)
.ToList();
}
}
private object GetKeyByValue(object searchValue)
{
foreach (DictionaryEntry entry in myHashTable)
{
if (entry.Value.Equals(searchValue))
{
return entry.Key;
}
}
return null;
}