如何使用SelectMany LINQ List <list <object >>并将其展平?

时间:2018-06-21 12:48:29

标签: c# linq lambda

class Player
{
    public int ID { get; set; }
    public string Name { get; set; }
}

void Main()
{   
    List<object> cricketPlayers = new List<object>();
    cricketPlayers.Add(new Player { ID = 1, Name = "Dhoni" });
    cricketPlayers.Add(new Player { ID = 2, Name = "Kohli" });
    cricketPlayers.Add(new Player { ID = 3, Name = "Gibbs" });
    cricketPlayers.Add(new Player { ID = 4, Name = "Ponting" });
    cricketPlayers.Add(new Player { ID = 5, Name = "Flintoff" });

    List<object> footBallPlayers = new List<object>();
    footBallPlayers.Add(new Player { ID = 6, Name = "Ronaldinho" });
    footBallPlayers.Add(new Player { ID = 7, Name = "Messi" });
    footBallPlayers.Add(new Player { ID = 8, Name = "Ronaldo" });

    List<object> tennisPlayers = new List<object>();
    tennisPlayers.Add(new Player { ID = 9, Name = "Federer" });
    tennisPlayers.Add(new Player { ID = 10, Name = "Nadal" });

    List<object> players = new List<object>();
    players.Add(cricketPlayers);
    players.Add(footBallPlayers);
    players.Add(tennisPlayers);

    players.Dump();
}

Please click here to view the Result image

我在LINQPad中执行了上述C#程序,并在图像中给出了结果。我需要编写一个Lambda Expression LINQ以仅获取十个播放器对象(SelectMany ???)。请让我知道如何通过LINQ(不使用循环)进行此操作。

PS:

我从API获得“玩家”列表。我无法更改API以其他方式返回玩家列表。

8 个答案:

答案 0 :(得分:2)

如果这是您需要的所有信息,那么您只需选择每个列表即可将它们合并为一个扁平的列表。

players.SelectMany(list => list);

我建议将它们分组(用.GroupBy()或给他们更多信息,因为当您弄平列表时会丢失信息,即哪个运动员在玩什么运动-该信息目前仅是列表的一部分

答案 1 :(得分:2)

尝试:

List<Players> players = new List<Players>();
players.AddRange(cricketPlayers);
players.AddRange(footBallPlayers);
players.AddRange(tennisPlayers);

然后它们都将在同一列表中

答案 2 :(得分:2)

由于您有一个实际上包含List<object>的{​​{1}},并且您希望在一个大列表中获得一个球员列表。不幸的是,由于某些外部原因,您无法更改API以提供合理类型的数据,因此您需要经历几次麻烦。因此,鉴于此:

List<List<Player>>

您可以使用List<object> players = <snip>; 通过强制转换来提取Player个对象的列表:

SelectMany

答案 3 :(得分:0)

假设您希望所有播放器对象都在一个列表中,则可以执行以下操作:

var players = cricketPlayers.Concat(footBallPlayers).Concat(tennisPlayers);

您的列表可能还应该是Player类型,而不是object

答案 4 :(得分:0)

这样会更好吗?

enum Sport
{
    Cricket,
    Fooball,
    Tennis
}

class Player
{
    public int ID { get; set; }
    public string Name { get; set; }
    public Sport Sport { get; set; }
}

void Main()
{
    List<Player> players = new List<Player>();

    players.Add(new Player { ID = 1, Name = "Dhoni", Sport = Sport.Cricket });
    players.Add(new Player { ID = 2, Name = "Kohli", Sport = Sport.Cricket });
    players.Add(new Player { ID = 3, Name = "Gibbs", Sport = Sport.Cricket });
    players.Add(new Player { ID = 4, Name = "Ponting", Sport = Sport.Cricket });
    players.Add(new Player { ID = 5, Name = "Flintoff", Sport = Sport.Cricket });

    players.Add(new Player { ID = 6, Name = "Ronaldinho", Sport = Sport.Fooball });
    players.Add(new Player { ID = 7, Name = "Messi", Sport = Sport.Fooball });
    players.Add(new Player { ID = 8, Name = "Ronaldo", Sport = Sport.Fooball });

    players.Add(new Player { ID = 9, Name = "Federer", Sport = Sport.Tennis });
    players.Add(new Player { ID = 10, Name = "Nadal", Sport = Sport.Tennis });

    players.Select(p => p.Name).Dump();
    players.Where(p => p.Sport == Sport.Fooball).Select(p => p.Name).Dump();
}

答案 5 :(得分:0)

更改下面的代码部分,

players.Add(cricketPlayers);
players.Add(footBallPlayers);
players.Add(tennisPlayers);    

对此,

players.AddRange(cricketPlayers);
players.AddRange(footBallPlayers);
players.AddRange(tennisPlayers);

答案 6 :(得分:0)

已解决,更改玩家列表的定义:

List<List<object>> players = new List<List<object>>();

并使用players.SelectMany(x=>x).ToList().Dump();

class Player
{
    public int ID { get; set; }
    public string Name { get; set; }
}

void Main()
{   
    List<object> cricketPlayers = new List<object>();
    cricketPlayers.Add(new Player { ID = 1, Name = "Dhoni" });
    cricketPlayers.Add(new Player { ID = 2, Name = "Kohli" });
    cricketPlayers.Add(new Player { ID = 3, Name = "Gibbs" });
    cricketPlayers.Add(new Player { ID = 4, Name = "Ponting" });
    cricketPlayers.Add(new Player { ID = 5, Name = "Flintoff" });

    List<object> footBallPlayers = new List<object>();
    footBallPlayers.Add(new Player { ID = 6, Name = "Ronaldinho" });
    footBallPlayers.Add(new Player { ID = 7, Name = "Messi" });
    footBallPlayers.Add(new Player { ID = 8, Name = "Ronaldo" });

    List<object> tennisPlayers = new List<object>();
    tennisPlayers.Add(new Player { ID = 9, Name = "Federer" });
    tennisPlayers.Add(new Player { ID = 10, Name = "Nadal" });

    List<List<object>> players = new List<List<object>>();
    players.Add(cricketPlayers);
    players.Add(footBallPlayers);
    players.Add(tennisPlayers);

    players.SelectMany(x=>x).ToList().Dump();
}

Result

答案 7 :(得分:0)

您的代码存在的问题是,Add不会将子列表的元素添加到players,而只是添加cricktePlayer实例本身。 List<Player>也是object。因此,以下内容当然只会在您的object列表中添加三个列表对象。

List<object> players = new List<object>();
players.Add(cricketPlayers);
players.Add(footBallPlayers);
players.Add(tennisPlayers);

如果您要打印这些lis,例如通过以下方式:

foreach(var l in players)
    Console.WriteLine(l);

您将获得以下内容:

System.Collections.Generic.List'1'.
System.Collections.Generic.List'1'.
System.Collections.Generic.List'1'.

这表明您没有将子列表的元素放入players列表中,而是子列表本身。换句话说,您没有List<Player>,但是有List<List<Player>>。因此,players中的每个元素本身都是List<Player>,而不是Player

这就是为什么其他人建议先将players设为List<Player>,然后再使用AddRange的原因。

但是由于某种原因似乎无法实现,您必须循环子列表中的每个元素,然后将当前元素添加到player-list中:

foreach(var p in cricktePlayers)
    players.Add(p);

事实上,基于linq的方法将完全一样,它只会向您隐藏这些循环。

幸运,使用AddRange可以更方便地做到这一点:

players.AddRange(cricketPlayers.Cast<Player>());

这甚至不是LINQ,但是也会循环cricketPlayers列表。因此,实际上,没有办法神奇地绕过列表循环。您所能做的就是保存一些代码行。