使用Linq构建和过滤笛卡尔积(自定义对象)

问题描述 投票:1回答:1

我有一个对象列表:

public class Item
{
    public int Id { get; set; }
    public Slot Slot { get; set; }
    public List<string> Spells { get; set; }
}

Slot是一个枚举:

public enum Slot
{
    Necklace = 1,
    Ring = 2,
    Bracelet = 3
}

我正在寻找的最终笛卡尔产品是适合以下对象类型的集合:

public class Set
{
    public int Necklace { get; set; }
    public int LeftBrace { get; set; }
    public int RightBrace { get; set; }
    public int LeftRing { get; set; }
    public int RightRing { get; set; }
}
  • 每个项目每套只能使用一次。
  • Set中的每个int属性都引用Item.Id
  • 项目只能放入指定的插槽,不能多次添加到集合中。
  • 如果一个集合包含多个项目上的重复咒语,则不应将其添加到笛卡尔积中;如果不可能,则从结果枚举中过滤掉。
  • 物品上的咒语可以是最少一个,最多四个,并且不能在物品本身上重复。

以下是我要构建笛卡尔积的集合。这些中的每一个都从项目的主要列表派生而来:

var _neckItems = _filterList.Where(i => i.Slot.Contains(Slot.Necklace)).ToArray();
var _leftRingItems = _filterList.Where(i => i.Slot.Contains(Slot.Ring)).ToArray();
var _rightRingItems = _filterList.Where(i => i.Slot.Contains(Slot.Ring)).ToArray();
var _leftBraceItems = _filterList.Where(i => i.Slot.Contains(Slot.Bracelet)).ToArray();
var _rightBraceItems = _filterList.Where(i => i.Slot.Contains(Slot.Bracelet)).ToArray();

这里是我设置笛卡尔积的方法:

Item[][] items = {
    _neckItems,
    _leftRingItems,
    _rightRingItems,
    _leftBraceItems
};

var sets = CartesianHelper.CartesianProduct(items);

这是笛卡尔方法本身:

public static IEnumerable<IEnumerable<T>> CartesianProduct<T>(this IEnumerable<IEnumerable<T>> sequences)
{
    IEnumerable<IEnumerable<T>> emptyProduct = new[] { Enumerable.Empty<T>() };
    return sequences.Aggregate(
        emptyProduct,
        (accumulator, sequence) =>
            from accseq in accumulator
            from item in sequence
            select accseq.Concat(new[] { item }));
}

这是将枚举投影到集合的方式:

var projectedSets = from s in sets.GroupBy(s => s.SelectMany(ss => ss.Spells).Distinct()).Select(x => x.First())
    where s.ToArray()[1].Id != s.ToArray()[2].Id
    && s.ToArray()[3].Id != s.ToArray()[4].Id
    select new Set
    {
        Necklace = s.ToArray()[0].Id,
        LeftRing = s.ToArray()[1].Id,
        RightRing = s.ToArray()[2].Id,
        LeftBrace = s.ToArray()[3].Id,
        RightBrace = s.ToArray()[4].Id,
    };

因此,总体而言,这是一个好的开始,我看到了结果。但是,当我向笛卡尔积中添加两个以上的集合时,结果呈指数增长,并且该应用程序变得无响应。

我的linq查询分组有问题,因为它没有过滤掉集合中的重复拼写,也许最好在达到这一点之前修改笛卡尔方法。

我想拥有的最后一个条件是能够考虑任何给定集中的空位。最终目标是确定给定的一组项目清单所覆盖的最大插槽数量。还应注意,我上面列出的插槽在最终解决方案中实际上仅是15个插槽中的3个。

编辑-我要澄清的是,最终结果是给定项目的最大覆盖插槽数和最大唯一法术数量。

感谢您的见解和帮助!

我有一个对象列表:公共类Item {public int Id {get;组; } public Slot Slot {get;组; } public List Spells {get;组; }}槽是一个枚举:public ...

c# .net linq cartesian-product
1个回答
0
投票

请在下面找到执行任意数量的整数数组的笛卡尔积的步骤。

© www.soinside.com 2019 - 2024. All rights reserved.