Reputation: 119
I have a this list:
List<myobject> list= new List<myobject>();
list.Add(new myobject{name="n1",recordNumber=1});
list.Add(new myobject{name="n2",recordNumber=2});
list.Add(new myobject{name="n3",recordNumber=3});
list.Add(new myobject{name="n4",recordNumber=3});
I'm looking for the fastest way to select distinct objects based on recordNumber, but if there is more than one object with same recordNumber(here recordNumber=3), I want to select object base on its name.(the name provided by paramater)
thanks
Upvotes: 1
Views: 2820
Reputation: 3917
If the name and recordNumber combination is guaranteed to be unique then you can always use Hashset.
You can then use RecordNumber and Name to generate the HashCode by using a method described here.
class myobject
{
//override GetHashCode
public override int GetHashCode()
{
unchecked // Overflow is fine, just wrap
{
int hash = 17;
// Suitable nullity checks etc, of course :)
hash = hash * 23 + recordNumber.GetHashCode();
hash = hash * 23 + name.GetHashCode();
return hash;
}
}
//override Equals
}
Upvotes: 0
Reputation: 117029
Here's the LINQ way of doing this:
Func<IEnumerable<myobject>, string, IEnumerable<myobject>> getDistinct =
(ms, n) =>
ms
.ToLookup(x => x.recordNumber)
.Select(xs => xs.Skip(1).Any()
? xs.Where(x => x.name == n).Take(1)
: xs)
.SelectMany(x => x)
.ToArray();
I just tested this with a 1,000,000 randomly created myobject
list and it produced the result in 106ms. That should be fast enough for most situations.
Upvotes: 2
Reputation: 4171
Are you looking for
class Program
{
static void Main(string[] args)
{
List<myobject> list = new List<myobject>();
list.Add(new myobject { name = "n1", recordNumber = 1 });
list.Add(new myobject { name = "n2", recordNumber = 2 });
list.Add(new myobject { name = "n3", recordNumber = 3 });
list.Add(new myobject { name = "n4", recordNumber = 3 });
//Generates Row Number on the fly
var withRowNumbers = list
.Select((x, index) => new
{
Name = x.name,
RecordNumber = x.recordNumber,
RowNumber = index + 1
}).ToList();
//Generates Row Number with Partition by clause
var withRowNumbersPartitionBy = withRowNumbers
.OrderBy(x => x.RowNumber)
.GroupBy(x => x.RecordNumber)
.Select(g => new { g, count = g.Count() })
.SelectMany(t => t.g.Select(b => b)
.Zip(Enumerable.Range(1, t.count), (j, i) => new { Rn = i, j.RecordNumber, j.Name}))
.Where(i=>i.Rn == 1)
.ToList();
//print the result
withRowNumbersPartitionBy.ToList().ForEach(i => Console.WriteLine("Name = {0} RecordNumber = {1}", i.Name, i.RecordNumber));
Console.ReadKey();
}
}
class myobject
{
public int recordNumber { get; set; }
public string name { get; set; }
}
Result:
Name = n1 RecordNumber = 1
Name = n2 RecordNumber = 2
Name = n3 RecordNumber = 3
Upvotes: 1
Reputation: 28698
Are you looking for a method to do this?
List<myobject> list= new List<myobject>();
list.Add(new myobject{name="n1",recordNumber=1});
list.Add(new myobject{name="n2",recordNumber=2});
list.Add(new myobject{name="n3",recordNumber=3});
list.Add(new myobject{name="n4",recordNumber=3});
public myobject Find(int recordNumber, string name)
{
var matches = list.Where(l => l.recordNumber == recordNumber);
if (matches.Count() == 1)
return matches.Single();
else return matches.Single(m => m.name == name);
}
This will - of course - break if there are multiple matches, or zero matches. You need to write your own edge cases and error handling!
Upvotes: 0
Reputation: 150108
It looks like you are really after something like:
Dictionary<int, List<myobject>> myDataStructure;
That allows you to quickly retrieve by record number. If the List<myobject>
with that dictionary key contains more than one entry, you can then use the name to select the correct one.
Note that if your list is not terribly long, an O(n) check that just scans the list checking for the recordNumber and name may be fast enough, in the sense that other things happening in your program could obscure the list lookup cost. Consider that possibility before over-optimizing lookup times.
Upvotes: 2