不仅从数组中获取重复项,还需要重复项的索引

时间:2011-07-15 17:41:48

标签: c# c#-4.0 linq-to-objects

我有以下数组:

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");

我希望获得所有重复项 - 名称一次,然后是重复项所在的位置(索引)。因此,在这种情况下,我希望获得“迈克尔·舒马赫”以及第1和第2位(指数0和1)。

这可以一次完成,还是我需要考虑其他选择?我刚刚在DotNetPearls上看到,与拥有自己的逻辑相比,IndexOf相当慢。

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());

3 个答案:

答案 0 :(得分:1)

为了利用linq,您可以编写类似下面的内容,它使用Select的重载,允许您获取元素索引,然后执行GroupBy操作。

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) });

这将产生一系列具有属性

的匿名类型对象
class Anon
{
    public string Name;
    public IEnumerable<int> Indexes;
}

您可以在

中使用
foreach (var item in query)
{
    Console.WriteLine(item.Name);
    foreach (int index in item.Indexes)
        Console.WriteLine(index);
}

当然,您可以更改分组以获取整个驱动程序对象的方式。

答案 1 :(得分:0)

下面的代码将为您提供一个由驱动程序名称键入的字典,其值为原始数组中的所有位置。它还将为您提供一个唯一的列表(HashSet),其中仅包含在原始数组中多次出现的驱动程序名称。

      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};
        }
      }

答案 2 :(得分:0)

鉴于Driver类的明确定义,这应该给你你想要的东西:

        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);