c# - 按其包含的项目对项目进行分组

标签 c# algorithm sorting grouping

请注意:我的问题包含伪代码!

在我的军队中,我有步兵。 每个士兵都是独一无二的:名字、力量等……

所有士兵都有元素栏。它可以是空的。 元素栏可以包含:武器、盾牌和其他元素。

我想根据他们的确切库存对我的步兵进行分组。

非常简单的例子:

我收藏了:

  • 武器:{“AK-47”、“手榴弹”、“刀”
  • 盾牌:{“宙斯盾”}
  • 其他项目:{"KevlarVest"}

步兵的集合。 (计数 = 6)

  • “乔”:{“AK-47”,“凯夫拉尔背心”}
  • “弗雷德”:{“AK-47”}
  • “约翰”:{“AK-47”,“手榴弹”}
  • “兰博”:{“刀”}
  • “Foo”:{“AK-47”}
  • “酒吧”:{“KevlarVest”}

这些是结果组(count=5):(现在已经按特定顺序排列)

  • {“AK-47”}
  • {"AK-47", "手榴弹"}
  • {“AK-47”,“凯夫拉背心”}
  • {“刀”}
  • {“凯夫拉背心”}

我想按以下方式对组进行排序:武器,然后是盾牌,然后是其他元素,按照它们在其收藏中声明的特定顺序。

当我打开库存组 {"Knife"} 时,我会找到一个包含 1 个名为“Rambo”的步兵的集合。

请注意:我制作了这个简化版本,以免您因手头数据的复杂性而分心。在我的业务案例中,我使用的是 ConditionalActionFlags,它可能包含某种类型的条件。

我特此提供一个现在仍然失败的 TestMethod。 能否重写 GetSoldierGroupings 方法,使 TestSoldierGroupings 方法成功?

public class FootSoldier
{
    public string Name { get; set; }
    public string[] Inventory { get; set; }
}

public class ArrayComparer<T> : IEqualityComparer<T[]>
{
    public bool Equals(T[] x, T[] y)
    {
        return x.SequenceEqual(y);
    }

    public int GetHashCode(T[] obj)
    {
        return obj.Aggregate(string.Empty, (s, i) => s + i.GetHashCode(), s => s.GetHashCode());
    }
}

[TestMethod]
public void TestSoldierGroupings()
{
    //Arrange
    var weapons = new[] { "AK-47", "Grenade", "Knife" };
    var shields = new[] { "Aegis" };
    var otherItems = new[] { "KevlarVest" };

    var footSoldiers = new FootSoldier[]
    {
        new FootSoldier() { Name="Joe" , Inventory= new string[]{ "AK-47", "Kevlar Vest" } },
        new FootSoldier() { Name="Fred" , Inventory= new string[]{ "AK-47" } },
        new FootSoldier() { Name="John" , Inventory= new string[]{ "AK-47", "Grenade" } },
        new FootSoldier() { Name="Rambo" , Inventory= new string[]{ "Knife" } },
        new FootSoldier() { Name="Foo" , Inventory= new string[]{ "AK-47" } },
        new FootSoldier() { Name="Bar" , Inventory= new string[]{ "Kevlar Vest" } }
    };

    //Act
    var result = GetSoldierGroupings(footSoldiers, weapons, shields, otherItems);
    //Assert
    Assert.AreEqual(result.Count, 5);
    Assert.AreEqual(result.First().Key, new[] { "AK-47" });
    Assert.AreEqual(result.First().Value.Count(), 2);
    Assert.AreEqual(result.Last().Key, new[] { "Kevlar Vest" });
    Assert.AreEqual(result[new[] { "Knife" }].First().Name, "Rambo");
}

public Dictionary<string[], FootSoldier[]> GetSoldierGroupings(FootSoldier[] footSoldiers, 
    string[] weapons, 
    string[] shields, 
    string[] otherItems)
{
    //var result = new Dictionary<string[], FootSoldier[]>();
    var result = footSoldiers
        .GroupBy(fs => fs.Inventory, new ArrayComparer<string>())
        .ToDictionary(x => x.Key, x => x.ToArray());

    //TODO: the actual sorting.

    return result;
}

最佳答案

您需要按组合项目的键对您的士兵进行分组。可以使用自定义比较器来完成。
至于我,我会通过使用带有分隔符的 String.Join 来简化它,这在任何武器、盾牌等中都无法满足。

假设一名士兵有一个属性Items,它是一个字符串数组(比如["AK-47", "Kevlar Vest"]),你可以这样做像这样:

var groups = soldiers
    .GroupBy(s => String.Join("~~~", s.Items))
    .ToDictionary(g => g.First().Items, g => g.ToArray()); 

它会生成一个字典,其中键是唯一的项目集,值是所有具有该集的士兵的数组。

您可以更改此代码,使其返回 IGrouping、类数组\结构、Dictionary,以及您方便的任何其他内容。
我会选择一个 Dictionary 或类似 SoldiersItemGroup[] 的数组,将元素和士兵作为属性。
确保更改这样的连接分隔符,理论上任何武器都无法包含它。

关于c# - 按其包含的项目对项目进行分组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41184575/

相关文章:

algorithm - 以数值方式求解具有二元变量的多元非线性方程组的最快方法是什么?

ios - 根据与特定属性相对应的另一个数组中的值对对象数组进行排序

sorting - 如何按幂 bi 矩阵的降序对列日期进行排序

java - C# 相当于 Java 的同步 (abc.class)

algorithm - Rust 中是否有等同于 C++ std::copy 的东西?

Javascript 合并行与条件

c++ - 在 C++ 中给出两个整数 vector (相同的大小和类型),我想将其中一个从最小元素到最大元素排序并更改第二个 vector 的顺序

c# - 数据库初始化后无法禁用迁移

c# - 使用 await 时 Monitor.Exit 上的 SynchronizationLockException

c# - XNA GameComponent 实现首选项...?