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();
Related
This question has been asked in one or the other way on SO but not like this. I just came over a very basic issue where I was looking for a statisfying solution :-)
I got a list of objects which have two integer properties. Now I want to find the max value of both properties of all object in the list.
I came up with three solutions:
First approach:
int max = Math.Max(list.Max(elem => elem.Nr), list.Max(elem => elem.OtherNr));
Second approach:
public int Max(List<Thing> list)
{
int maxNr = 0;
foreach (var elem in list)
{
if (elem.Nr > maxNr)
maxNr = elem.Nr;
if (elem.OtherNr > maxNr)
maxNr = elem.OtherNr;
}
return maxNr;
}
A third approach would be to do the sorting by both attribute and then just take the first entry and get the one or the other property.
I would like to find the fastest way to do this. So of all approaches I like the second one the post (from the performace point of view). Even though the first one is shorter you have to go through the list twice.
Any other solutions?
If you do
int max = list.Max(elem => Math.Max(elem.Nr, elem.OtherNr));
it's still a single-liner but only iterates through the list once. I'd take the single-linedness over the probable slight reduction in efficiency from writing it out by hand.
(Also, don't you need a cast from double to int somewhere in there?)
An alternative solution using LINQ if you need more than 2 properties (which is the limit of Math.Max):
int max = list
.SelectMany(elem => new[]{ elem.Prop1, elem.Prop2, elem.Prop3 })
.Max();
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));
}
I have a class contain many variables, something like that
class test
{
internal int x , y ;
internal string z;
}
I created a list of this class list<test> c
I want to do the following:
test if all the list items contain the same x
get the list's item that has z = "try"
I need a quick and fast way , instead of iterate though the entire items
Any suggestion please ,
LINQ to Objects is your friend. For the first:
bool allSameX = list.All(t => t.x == list[0].x);
Test firstTry = list.First(t => t.z == "try");
Test firstTryOrNull = list.FirstOrDefault(t => t.z == "try");
The first one depends on there being at least one value of course. Alternatives might be:
bool allSameX = !list.Select(t => t.x)
.Distinct()
.Skip(1)
.Any();
In other words, once you've gone past the first distinct value of x, there shouldn't be any more. One nice aspect of this is that as soon as it spots the second distinct value, it will stop looking - as does the first line (the All version) of course.
LINQ is wonderfully flexible, and well worth looking into closely.
EDIT: If you need to do the latter test ("find an element with a particular value for z") for multiple different values, you might want a dictionary or a lookup, e.g.
// If there are duplicate z values
var lookup = list.ToLookup(t => t.z);
// If z values are distinct
var dictionary = list.ToDictionary(t => t.z);
Without some pre-work, there's no way of performing the queries you want without iterating over at least some of the list.
You can use linq. Here is a link to small examples that will help you a lot for future too http://msdn.microsoft.com/en-us/vcsharp/aa336746
You could implement a custom collection class instead of a list, and put the search smarts into this e.g.
add a method AllItemsHaveSameX() and a private bool field allItemsHaveSameX
expose a dictionary keyed by the search strings with the index of the item that has that value.
When adding/removing items:
You would re-evaluate allItemsHaveSameX
Add/remove from your private dictionary.
I am trying to get a random object within linq. Here is how I did.
//get all the answers
var Answers = q.Skip(1).Take(int.MaxValue);
//get the random number by the number of answers
int intRandomAnswer = r.Next(1, Answers.Count());
int count = 0;
//locate the answer
foreach(var Answer in Answers)
{
if (count == intRandomAnswer)
{
SelectedPost = Answer;
break;
}
count++;
}
Is this the best way to do this?
What about:
SelectedPost = q.ElementAt(r.Next(1, Answers.Count()));
Further reading:
The comments below make good contributions to closely related questions, and I'll include them here, since as #Rouby points out, people searching for an answer to these may find this answer and it won't be correct in those cases.
Random Element Across Entire Input
To make all elements a candidate in the random selection, you need to change the input to r.Next:
SelectedPost = Answers.ElementAt(r.Next(0, Answers.Count()));
#Zidad adds a helpful extension method to get random element over all elements in the sequence:
public static T Random<T>(this IEnumerable<T> enumerable)
{
if (enumerable == null)
{
throw new ArgumentNullException(nameof(enumerable));
}
// note: creating a Random instance each call may not be correct for you,
// consider a thread-safe static instance
var r = new Random();
var list = enumerable as IList<T> ?? enumerable.ToList();
return list.Count == 0 ? default(T) : list[r.Next(0, list.Count)];
}
Another wacky approach (not the most efficient for larger data sets):
SelectedPost = q.OrderBy(qu => Guid.NewGuid()).First();
Use a Fisher-Yates-Durstenfeld shuffle.
(You could use a helper/extension method to shuffle your IEnumerable<T> sequence. Alternatively, if you were using an IList<T> you could perform an in-place shuffle, if you prefer.)
Generic extension method based on the accepted answer (which doesn't always skip the first, and only enumerates the enumerable once):
public static class EnumerableExtensions
{
public static T Random<T>(this IEnumerable<T> enumerable)
{
var r = new Random();
var list = enumerable as IList<T> ?? enumerable.ToList();
return list.ElementAt(r.Next(0, list.Count()));
}
}
Late to the party but this is a high-up Google result. A succinct version could be:
var rnd = new Random();
var SelectedPost = q.OrderBy(x => rnd.Next()).Take(1);
It has the disadvantage that it'll apply a random number to all elements, but is compact and could easily be modified to take more than one random element.
var rand = new Random();
var selectedPost = q.Skip(rand.Next(0, q.Count())).Take(1).FirstOrDefault();
Optimally, you want to only ever make the function query for a single value, so you set up the Skip/Take to jump up to the sequence number matching the random number you're generating (bounded by dataset's itemcount, so the missing row problem bounding based on MAX(pkey) isn't an issue) and then snag the first item at that point in the sequence.
In SQL this is the same as querying for SELECT Count(*) FROM q, then SELECT * FROM q LIMIT {0}, 1 where {0} is rand.Next(0, count), which should be pretty efficient.
Pulling all of the answers and looping them isn't the most efficient way as you're moving lots of data from the database. If you're using an integer primary key that's automatically incrementing, you should get the Max of your primary key and then find the random integer within that range. Then directly get the single answer based on the primary key derived from the random function.
I'm posting an answer because I don't have enough reputation to comment.
I like this answer:
SelectedPost = q.ElementAt(r.Next(1, Answers.Count()));
But ElementAt is zero based, surely starting at 1 and going to Answers.Count() you are going to end up potentially throwing an out of range, and you are never going to get the first entity.
Wouldn't
SelectedPost = q.ElementAt(r.Next(0, Answers.Count() - 1));
Be better?
I have product table in database ,every time user enters one product detail I want to show 10 similar products in below of page.And in every refresh this list must be change .it must come randomly.
Linq looks like this
var products =
DataContextFactory.GetDataContext()
.Set<Product>()
.Where(x =>x.Id!=id)
.OrderBy(emp => Guid.NewGuid())
.Take(10).ToList();
x.Id!=id
this only for not put selected product to list .
It works perfect
I'm having issues finding the most efficient way to remove duplicates from a list of strings (List).
My current implementation is a dual foreach loop checking the instance count of each object being only 1, otherwise removing the second.
I know there are MANY other questions out there, but they all the best solutions require above .net 2.0, which is the current build environment I'm working in. (GM and Chrysler are very resistant to changes ... :) )
This limits the possible results by not allowing any LINQ, or HashSets.
The code I'm using is Visual C++, but a C# solution will work just fine as well.
Thanks!
This probably isn't what you're looking for, but if you have control over this, the most efficient way would be to not add them in the first place...
Do you have control over this? If so, all you'd need to do is a myList.Contains(currentItem) call before you add the item and you're set
You could do the following.
List<string> list = GetTheList();
Dictionary<string,object> map = new Dictionary<string,object>();
int i = 0;
while ( i < list.Count ) {
string current = list[i];
if ( map.ContainsKey(current) ) {
list.RemoveAt(i);
} else {
i++;
map.Add(current,null);
}
}
This has the overhead of building a Dictionary<TKey,TValue> object which will duplicate the list of unique values in the list. But it's fairly efficient speed wise.
I'm no Comp Sci PhD, but I'd imagine using a dictionary, with the items in your list as the keys would be fast.
Since a dictionary doesn't allow duplicate keys, you'd only have unique strings at the end of iteration.
Just remember when providing a custom class to override the Equals() method in order for the Contains() to function as required.
Example
List<CustomClass> clz = new List<CustomClass>()
public class CustomClass{
public bool Equals(Object param){
//Put equal code here...
}
}
If you're going the route of "just don't add duplicates", then checking "List.Contains" before adding an item works, but its O(n^2) where n is the number strings you want to add. Its no different from your current solution using two nested loops.
You'll have better luck using a hashset to store items you've already added, but since you're using .NET 2.0, a Dictionary can substitute for a hash set:
static List<T> RemoveDuplicates<T>(List<T> input)
{
List<T> result = new List<T>(input.Count);
Dictionary<T, object> hashSet = new Dictionary<T, object>();
foreach (T s in input)
{
if (!hashSet.ContainsKey(s))
{
result.Add(s);
hashSet.Add(s, null);
}
}
return result;
}
This runs in O(n) and uses O(2n) space, it will generally work very well for up to 100K items. Actual performance depends on the average length of the strings -- if you really need to maximum performance, you can exploit some more powerful data structures like tries make inserts even faster.