试图找出一个c# linq的对象列表,可以用多个类别标记,

utugiqy6  于 12个月前  发布在  C#
关注(0)|答案(3)|浏览(161)

| 实体清单|标签类别|
| --|--|
| entity1|(cat1,cat2,cat3)|
| 实体2|(cat2,cat4,cat5)|
| 实体3|(cat1,cat3,cat5)|
| 实体4|(cat2,cat3)|
| 实体5|(cat1,cat4,cat5)|

Class Entity
{           
  Entity Name;
  List<Category> Categories 
}
 
var listentities= somemethod(); //returns List<Entity>  <br>

字符串
预期产出:
| - -|- -|
| --|--|
| cat1|实体1、实体3、实体5|
| cat2|实体2,实体4|
| cat3|实体1、实体3、实体4|
注意:我使用2个foreach循环和字典得到了想要的输出,但是我想使用linq。

m3eecexj

m3eecexj1#

为了直接回答你的问题,你可以使用SelectManyDistinct来得到你想要的,尽管正如我的评论所说,它可能不会比你已经做的更快:

Entity[] entities = [
    new("Ent 1", ["1", "2", "3"]),
    new("Ent 2", ["2", "4", "5"]),
    new("Ent 3", ["1", "3", "5"]),
    new("Ent 4", ["2", "3", ]),
    new("Ent 5", ["1", "4", "5"]),
];

var categories1 = entities
    .SelectMany(q => q.Categories)
    .Distinct()
    .Select(q => new Category(
        q,
        entities
            .Where(w => w.Categories.Contains(q))
            .Select(q => q.Name)
        .ToList()));

foreach (var cat in categories1)
{
    Console.WriteLine($"{cat.Name}: {string.Join(", ", cat.Entities)}");
}

public record Entity(string Name, List<string> Categories);
public record Category(string Name, List<string> Entities);

字符串

qybjjes1

qybjjes12#

或许:

listentities
    .SelectMany(e => e.Categories.Select(c => new {
        Entity = e,
        Category = c
     })
    .GroupBy(ec => ec.Category)
    .Select(g => new {
        Category = g.Key,
        Entities = g.Select(ec => ec.Entity).ToList()
    })
    .ToList();

字符串
这将实体数据扩展为{实体,类别}对,按类别分组,然后构建结果。
如果需要的话,最终的结果可以调整为只包含名称而不是对象引用。此外,如果你想的话,实体名称可以使用.Aggregate()String.Join()连接到一个字符串中。

  • 不确定.GroupBy(ec => ec.Category)。如果Category不是IEquatable,则可能需要.GroupBy(ec => ec.Category.Name),在这种情况下,后面的Category = g.Key需要更改为Category = g.First().Category。*
hujrc8aj

hujrc8aj3#

我将Entity类定义为

public class Entity(string name, List<string> categories)
{
    public string Name { get; } = name;

    public List<string> Categories { get; } = categories;
}

字符串
如果类别是自定义类型,则可能需要将其等同。
我将测试SomeMethod方法定义为

static List<Entity> SomeMethod()
{
    return new List<Entity>{
        new Entity("Ent 1", new List<string> { "1", "2", "3", }),
        new Entity("Ent 2", new List<string> { "2", "4", "5", }),
        new Entity("Ent 3", new List<string> { "1", "3", "5", }),
        new Entity("Ent 4", new List<string> { "2", "3", }),
        new Entity("Ent 5", new List<string> { "1", "4", "5", }),
    };
}

双循环-无Linq

首先,一种不使用Linq的方法。

var listEntities = SomeMethod();
var dict = new Dictionary<string, IList<Entity>>();
foreach (var entity in listEntities)
{
    foreach (var category in entity.Categories)
    {
        if (!dict.TryGetValue(category, out var value))
        {
            value = new List<Entity>();
            dict.Add(category, value);
        }

        value.Add(entity);
    }
}

foreach (var key in dict.Keys)
{
    Console.WriteLine($"{key}: {string.Join(", ", dict[key].Select(e => e.Name))}");
}


基本上,循环遍历Entity对象的列表,并循环遍历Entity对象中的类别以填充Dictionary。

Linq

这一次,使用Linq。

var listEntities = SomeMethod();
var groupByCategory =
    listEntities.SelectMany(e => e.Categories.Select(c => new { Category = c, Entity = e, }))
        .GroupBy(ce => ce.Category, (cat, ents) => new { Category = cat, Entities = ents });

foreach (var group in groupByCategory)
{
    Console.WriteLine($"{group.Category}: {string.Join(", ", group.Entities.Select(e => e.Entity.Name))}");
}


GroupBy的返回值大致相当于字典,可以通过提供resultSelector来“清理”一下。
这两种方法都产生以下输出:

1: Ent 1, Ent 3, Ent 5
2: Ent 1, Ent 2, Ent 4
3: Ent 1, Ent 3, Ent 4
4: Ent 2, Ent 5
5: Ent 2, Ent 3, Ent 5

相关问题