按项目项目对项目进行分组

时间:2016-12-16 12:36:17

标签: c# algorithm sorting grouping

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

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

所有士兵都有库存。它可以是空的。 库存可以包含:武器,盾牌,其他物品。

我想按照确切的库存对我的脚踏车进行分组。

非常简单的例子:

我有一个集合:

  • 武器:{“AK-47”,“手榴弹”,“刀”}
  • 希尔兹:{“Aegis”}
  • OtherItems:{“KevlarVest”}

脚踏车的收集。 (数= 6)

  • “Joe”:{“AK-47”,“Kevlar Vest”}
  • “Fred”:{“AK-47”}
  • “John”:{“AK-47”,“Grenade”}
  • “Rambo”:{“Knife”}
  • “Foo”:{“AK-47”}
  • “Bar”:{“KevlarVest”}

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

  • { “AK-47”}
  • {“AK-47”,“Grenade”}
  • {“AK-47”,“Kevlar Vest”}
  • { “刀”}
  • { “KevlarVest”}

我希望按以下方式对群组进行排序:武器,然后按盾牌,然后按照特定顺序对其中的其他项目进行排序。

当我打开库存组{“Knife”}时,我会找到一个名为“Rambo”的1英尺的集合。

请注意:我已经制作了这个简化版本,以免您分散手头数据的复杂性。在我的商业案例中,我正在使用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;
}

1 个答案:

答案 0 :(得分:1)

您需要通过组合项目的键对士兵进行分组。它可以使用自定义比较器完成 至于我,我会通过使用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,类\ structs数组,Dictionary,以及其他任何方便您的代码。
我会选择Dictionary或类似SoldiersItemGroup[]的数组,其中包含物品和士兵作为属性 确保更改这样的连接分隔符,理论上没有武器可以包含它。