C# 按其持有的项目对项目进行分组

C# 按其持有的项目对项目进行分组,c#,algorithm,sorting,grouping,C#,Algorithm,Sorting,Grouping,请注意:我的问题包含伪代码 我的军队里有步兵。 每个士兵都是独一无二的:名字、力量等等 所有士兵都有库存。它可以是空的。 库存可以包含:武器、盾牌、其他物品 我想根据步兵的确切数量对他们进行分组 非常简单的示例: 我收集了: 武器:{“AK-47”、“手榴弹”、“刀”} 盾牌:{“宙斯盾”} 其他项目:{“Kevlavest”} 步兵的集合。(计数=6) “乔”:{“AK-47”,“凯夫拉尔背心”} “弗雷德”:{“AK-47”} “约翰”:{“AK-47”,“手榴弹”} “兰博”:{“刀

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

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

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

我想根据步兵的确切数量对他们进行分组

非常简单的示例:

我收集了:

  • 武器:{“AK-47”、“手榴弹”、“刀”}
  • 盾牌:{“宙斯盾”}
  • 其他项目:{“Kevlavest”}
步兵的集合。(计数=6)

  • “乔”:{“AK-47”,“凯夫拉尔背心”}
  • “弗雷德”:{“AK-47”}
  • “约翰”:{“AK-47”,“手榴弹”}
  • “兰博”:{“刀”}
  • “Foo”:{“AK-47”}
  • “Bar”:{“Kevlavest”}
这些是结果组(计数=5):(现在已按特定顺序排列)

  • {“AK-47”}
  • {“AK-47”,“手榴弹”}
  • {“AK-47”,“凯夫拉尔背心”}
  • {“刀”}
  • {“Kevlavest”}
我想按照武器、盾牌、其他物品的特定顺序对这些物品进行分类,这些物品在它们的收藏中被申报

当我打开清单组{“刀”}时,我会找到一个集合,其中有一个名为“兰博”的步兵

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

在此,我提供了一个仍然失败的测试方法。 能否重写
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;
}
公共级步兵
{
公共字符串名称{get;set;}
公共字符串[]清单{get;set;}
}
公共类阵列比较程序:IEqualityComparer
{
公共布尔等于(T[]x,T[]y)
{
返回x.x(y);
}
public int GetHashCode(T[]obj)
{
返回obj.Aggregate(string.Empty,(s,i)=>s+i.GetHashCode(),s=>s.GetHashCode());
}
}
[测试方法]
public void TestSoldierGroupings()
{
//安排
var武器=新[]{“AK-47”、“手榴弹”、“刀”};
var shields=new[]{“宙斯盾”};
var otherItems=new[]{“Kevlavest”};
var步兵=新步兵[]
{
新步兵(){Name=“Joe”,Inventory=newstring[]{“AK-47”,“Kevlar背心”},
新步兵(){Name=“Fred”,Inventory=newstring[]{“AK-47”},
新步兵(){Name=“John”,Inventory=newstring[]{“AK-47”,“手榴弹”},
新步兵(){Name=“Rambo”,Inventory=newstring[]{“刀”},
新步兵(){Name=“Foo”,Inventory=newstring[]{“AK-47”},
新步兵(){Name=“Bar”,库存=新字符串[]{“Kevlar背心”}
};
//表演
var结果=获取士兵分组(步兵、武器、盾牌、其他物品);
//断言
Assert.AreEqual(result.Count,5);
AreEqual(result.First().Key,new[]{“AK-47”});
Assert.AreEqual(result.First().Value.Count(),2);
AreEqual(result.Last().Key,new[]{“Kevlar Vest”});
AreEqual(result[new[]{“Knife”}).First().Name,“Rambo”);
}
公共字典GetSoldierGroup(步兵[]步兵,
弦[]武器,
字符串[]屏蔽,
字符串[]其他项)
{
//var result=newdictionary();
var结果=步兵
.GroupBy(fs=>fs.Inventory,新的ArrayComparer())
.ToDictionary(x=>x.Key,x=>x.ToArray());
//TODO:实际排序。
返回结果;
}

您需要按组合物品键将士兵分组。可以使用自定义比较器进行此操作。
对我来说,我会使用
String.Join
和分隔符,这在任何武器、盾牌等中都不会遇到

假设士兵有一个属性
Items
,它是一个字符串数组(如
[“AK-47”,“Kevlar背心”]
),您可以这样做:

var groups = soldiers
    .GroupBy(s => String.Join("~~~", s.Items))
    .ToDictionary(g => g.First().Items, g => g.ToArray()); 
它将生成一个字典,其中键是唯一的项集,值是拥有该项集的所有士兵的数组

您可以更改此代码,使其返回
i分组
、类数组\structs、
字典
,任何其他方便的内容。
我想要一本
字典
或者一个类似于
士兵项目组[]
的数组,其中物品和士兵是属性。

确保更改这样的连接分隔符,使理论上没有武器可以容纳它。

Ohhh如果步兵的库存中没有物品,那是他们自己的一组,在排序的基础上:-)您可以枚举库存项目的可能组合,并将该枚举作为士兵声音的属性,如使用自定义比较器的标准LINQ
GroupBy
。你试过什么吗?有什么问题?@Tony_KiloPapaMikeGolf:根据您删除的问题:
\u appleTrees.SelectMany(atree=>atree.Basket.Apples.Where(a=>a.DNA.Contains(atree.TreeDNA))@TimSchmelter:谢谢你的帮助!我不敢回答问题,人们的投票速度太快了。我用过你的ToDictionary()方法。但我不得不加上一句:“公共类ArrayComparer:IEqualityComparer”。你能帮我排序吗,这样TestMethod就成功了?