首页 文章

从C#list <T>中提取唯一项目的简单方法,包括该类型项目的总数

提问于
浏览
2

如果这是不正确的地方,请道歉;我是一个非常新的业余爱好者 .

我正忙着在一个小型自上而下的射击游戏中工作,只不过是一个简单的自我驱动项目来学习和玩乐 . 我使用C#和XNA作为框架,我试图通过拾取gameObjects添加到库存中来添加一些变化 .

目前我有一个 List<GamePlayObjects> "WorldObjects"并且我有一个 ObjectManager 类来管理所有对象更新,碰撞和绘制功能,并且对我到目前为止感到满意 . 在与GamePlayObject发生碰撞时(例子可能是小行星炸毁后的一小块铁矿石),它会从主列表中删除对象"WorldObjects"并将其添加到另一个名为 List<GamePlayObjects> inventory 的列表中

现在我要做的是在屏幕上绘制一个小区域,其中包含项目精灵和我收集的项目总数 . 我对绘图方面并不感兴趣,更多的是提取库存中的数据 .

我已经阅读了几个线程,或许正在使用 HashSet 从我的库存中获取独特的项目,然后从 HashSet 中提取每个项目的总数,但我现在很难理解这一点,因此我在这里访问了一些帮助 .

Examples of my code and what im trying to achieve.

我有一个包含所有WorldObjects的列表每个世界Object是一个包含与该worlObject相关的所有内容的类 .

private List<GamePlayObject> gameObjects = new List<GamePlayObject>();

当一个对象,让我们说“玩家”与另一个对象“铁矿石”碰撞时,我从以下位置删除了IronOre世界对象:

private List<GamePlayObject> gameObjects = new List<GamePlayObject>();

并将其添加到名为Inventory的新列表中

private List<GamePlayObject> playerInventory = new List<GamePlayObject>();

现在,随着越来越多的对象被收集并添加到我的库存中,我想提取信息并将有关我的库存的信息显示在屏幕上 .

例如,在我的屏幕的右侧,我想提供我的库存中的项目列表以及每个项目的总金额,这些数据应该从我的库存清单中获取 .

所以它可能看起来像这样:

Iron Ore x 3
Steel x 10
Gold x 18
Uranium x 12

4 回答

  • 1

    您可以使用 List<T> ,并使用 List<T>.Remove . 但是,像这样使用 List<T> 的问题是 Remove 必须一次搜索整个列表,一个项目,以找到要删除的项目 . 这也会导致发生大型复制,因为您删除的元素之后的元素需要在内部数组中向下移动 .

    但是,像 HashSet<T> 这样的集合可以非常快速地找到和删除项目,而无需副本 . 这要求您的类型实现 GetHashCode ,但如果您总是需要唯一的项目,则会更好 .

    对于两个集合,一个可能的选择是使用 Dictionary<GamePlayObject, int> ,这将允许您快速查找并更改世界中该类型对象的数量和库存 . 同样,这将要求您的 GamePlayObject 类覆盖 object.GetHashCodeobject.Equals ,并实现IEquatable<GamePlayObject> .

  • 0

    现在我要做的是在屏幕上绘制一个小区域,其中包含项目精灵和我收集的项目总数 . 我对绘图方面并不感兴趣,更多的是提取库存中的数据 .

    听起来像你想要使用linq计数 .

    InventoryObjects.Count(inventoryObject => inventoryObject.Type == ObjectTypes.Asteroid);
    WorldObjects.Count(worldObject => worldObject.Type == ObjectTypes.Asteroid);
    

    你可以把它想象成SQL

    SELECT COUNT([dbo] . [World Objects] . [Object])WHERE [dbo] . [World Objects] . [Type] ='Asteroid'

    但是,如果您要提取项目并将其添加到另一个列表中,您应该接受Reed Copsey的建议 .


    Edit

    所以假设你有一个 Player 类,那么也许它的结构是这样的,

    Public Class Player {
        public List<GamePlayObject> Inventory {get; set;}
    }
    

    你也有一个 World 类,也许它有类似的,

    Public Class World {
        public List<GamePlayObject> Objects {get; set;}
    }
    

    你的_1310720可能看起来像这样,

    Public Class GamePlayObject {
        public ObjectType Type {get; set;}
    }
    

    因此,假设您已初始化您的世界并且它有多个对象,并且您知道要从所述世界中删除哪个对象 . 就资源和优化而言,这当然不是最好的方法(这将是Reed Copsey的答案会派上用场的地方)但是,你可以......

    var targetObject = World.Where(gamePlayObject => (DesiredConditions))
    World.Objects.Remove(targetObject);
    Player.Inventory.Add(targetObject);
    

    哪里 DesiredConditions 可能会像 gamePlayObject.IsCollidedWith

    完成此操作后,您可以查询 Player 的库存 .

    var IronCount = Player.Inventory.Count(gamePlayObject => gamePlayObject.Type == ObjectType.Iron);
    

    希望这可以解决问题 .

  • 0

    用linq解决这个问题听起来很棒!如果你're new to linq, then I' d指导你一个很好的资源 - 101 linq样本:http://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b

    关于你的特殊问题!自 List<T> 实施 IEnumerable<T> ,您可以对其运行linq查询 . 最有趣的是分组运算符 .

    如果您的 GamePlayObject 类具有 Type 属性,那么您可以执行以下操作:

    var items = from o in playerInventory
        group o by o.Type into g
        select new { ItemType = g.Key, Items = g };
    foreach (var g in items)
    {
        string s = string.Format("{0} x {1}", g.ItemType.ToString(), g.Items.Count());
        //now do whatever you want with the string, which will contain, eg, Iron Ore x 3
    }
    
  • 1

    听起来你可能不应该使用列表 . 这意味着为什么在需要保持不同游戏对象的计数时,为什么迭代到一个列表到一个列表 . 我假设你有一套固定的游戏对象并且它们具有独特的名称 . 您可以拥有一个固定的元素字典,您可以在其中添加或减去计数,这意味着您可能正在执行类似gameObjects [“ironore”]或playerInventory [“ironore”] - 的操作 . 然后您可以使用linq来显示其值大于零的所有键 .

相关问题