Not only get duplicates from array, but need as well index of the duplicates
I have the following array:
Driver[] predictions = new Driver[6];
predictions[0] = new Driver(10, "Michael Schumacher");
predictions[1] = new Driver(10, "Michael Schumacher");
predictions[2] = new Driver(9, "Fernando Alonso");
predictions[3] = new Driver(8, "Jensen Button");
predictions[4] = new Driver(7, "Felipe Massa");
predictions[5] = new Driver(6, "Giancarlo Fisichella");
I want to get all the duplicates - The name once, and then the positions (index) where the duplicates are. So, in this case I want to get "Michael Schumacher" and the positions 1 and 2 (index 0 and 1).
Can this be done in one go, or do I need to consider other options?开发者_开发知识库 I just read on DotNetPearls that IndexOf is pretty slow compared to having your own logic.
var driversSelectedMoreThanOnceAndTheirPositions = predictions.Select((driver, index) => new { driver, index })
.GroupBy(item => item.driver.Name)
.Where(grp => grp.Count() > 1)
.ToDictionary(g => g.Key, g => g.Select(a => (a.index + 1)).ToList());
To utilize linq for this, you could write something like the following, which uses an overload of Select
that allows you to get the element index and then performs a GroupBy
operation.
var query =
predictions.Select((driver, index) => new { driver, index })
.GroupBy(item => item.driver.Name)
.Where(grp => grp.Count() > 1)
.Select(grp => new { Name = grp.Key, Indexes = grp.Select(item => item.index) });
This will result in a sequence of anonymous-typed objects with the properties
class Anon
{
public string Name;
public IEnumerable<int> Indexes;
}
Which you could use as in
foreach (var item in query)
{
Console.WriteLine(item.Name);
foreach (int index in item.Indexes)
Console.WriteLine(index);
}
You can, of course, change the way you group to get the entire driver object.
The code below will give you a dictionary keyed by driver's name, with a value of all their positions in the original array. It will also give you a unique list (HashSet) containing only those driver names which occurred more than once in the orginal array.
Driver[] predictions = new Driver[6];
predictions[0] = new Driver(10, "Michael Schumacher");
predictions[1] = new Driver(10, "Michael Schumacher");
predictions[2] = new Driver(9, "Fernando Alonso");
predictions[3] = new Driver(8, "Jensen Button");
predictions[4] = new Driver(7, "Felipe Massa");
predictions[5] = new Driver(6, "Giancarlo Fisichella");
Dictionary<string, List<int>> indicies = new Dictionary<string, List<int>>();
HashSet<string> driversWithDups = new HashSet<string>();
for (int i=0; i<predictions.Length; i++)
{
Driver eachDriver = predictions[i];
if (indicies.ContainsKey(eachDriver.Name))
{
indicies[eachDriver.Name].Add(i);
driversWithDups.Add(eachDriver.Name);
}
else
{
indicies[eachDriver.Name] = new List<int>() {i};
}
}
Given the obvious definition of the Driver class, this should give you what you want:
Driver[] predictions = new Driver[6];
predictions[0] = new Driver(10, "Michael Schumacher");
predictions[1] = new Driver(10, "Michael Schumacher");
predictions[2] = new Driver(9, "Fernando Alonso");
predictions[3] = new Driver(8, "Jensen Button");
predictions[4] = new Driver(7, "Felipe Massa");
predictions[5] = new Driver(6, "Giancarlo Fisichella");
var ds = predictions.Select((driver, i) => new { Name = driver.Name, Index = i })
.GroupBy(a => a.Name, a => a.Index);
精彩评论