【问题标题】:Filtering a Key Value from a Dictionary in C#从 C# 中的字典中过滤键值
【发布时间】:2017-12-05 20:04:58
【问题描述】:

我是 C# 新手,目前正在尝试找出实现以下功能的最佳方法:

我有一个相关组的物种列表:

Bird: "Budgie", "Parrot"
Dog: "Pitbull", "Labrador"
Cat: "Cheetah", "Lion"

给定一串动物,我需要返回它的组。 例如。 “猎豹”将返回“猫”。

我已经实现了以下:

// create list one and store values
List<string> valSetOne = new List<string>();
valSetOne.Add("Budgie");
valSetOne.Add("Parrot");

// create list two and store values
List<String> valSetTwo = new List<String>();
valSetTwo.Add("Lion");
valSetTwo.Add("Cheetah");

// create list three and store values
List<String> valSetThree = new List<String>();
valSetThree.Add("Labrador");
valSetThree.Add("Pitbull");

// add values into map
map.Add("Bird", valSetOne);
map.Add("Cat", valSetTwo);
map.Add("Dog", valSetThree);

foreach(KeyValuePair<string, List<string>> kvp in map){
    foreach(string value in kvp.Value)
    {
       Console.WriteLine("Key = {0}, Value = {1}", kvp.Key, value);
    }
}

除了使用 foreach 循环之外,有没有更快的方法来找到给定动物值的键?

//编辑:

目前正在尝试使用元组进行初始化

var tupleList = new List<Tuple<string, List<string>>>
{
   new Tuple<string, List<string>>("cat", { "cheetah", "lion"})

};

我收到以下错误:意外符号 `{'

【问题讨论】:

  • 字典适合按键查找值,而不是相反。
  • 是的,你可以,但这不是正确的方式,你必须使用类,c# 是 OOP 语言
  • @jonathana 创建类是一种工具。它对解决某些问题很有用,而对其他问题则无用。除了显示的 sn-p 中的代码需要在某个对象的某个成员中之外,我看不出有什么理由需要创建任何新对象来解决这个特定问题。
  • 如果您希望能够轻松查找动物的类别,请创建一个将每个动物映射到其类别的查找。
  • 你不能只写, { "...."}。你需要new List&lt;string&gt; {...}。请参阅下面的更新

标签: c# dictionary filter


【解决方案1】:

更好的数据建模方法是创建一个组类,其中包含一个名称和一组动物。然后你可以持有一组组并查询它。

如果您想坚持使用字典,则:由于您的问题是从该键的值列表中检索给定 valuekey,因此我会以相反的方式组织数据:

var map = new Dictionary<string,string>
{
    ["Cheetah"] = "Cat",
    ["Lion"] = "Cat",
    //....
};

然后你就可以用你真正的关键字搜索了——这是物种而不是群体:

if(map.TryGetValue("Lion", out var group)) { }

由于通过分组到物种列表来构建数据更容易,因此您可以:

var rawData = new List<(string group, List<string> species)>
{
    ("Cat", new List<string> { "Cheetah", "Lion" }),
    //...
};

var result = rawData.SelectMany(item => item.species.Select(s => (s, item.group)))
                    .ToDictionary(k => k.s, v => v.group);

这适用于 C#7.0 命名元组。如果您使用的是以前的版本,您可以使用匿名类型或“老式”元组

对于集合的 C# 7.0 之前的初始化:

var rawData = new List<Tuple<string, List<string>>>
{
    Tuple.Create<string,List<string>> ("Cat", new List<string> { "Cheetah", "Lion" })
};

【讨论】:

  • 我喜欢这种方法。我正在尝试构建组列表,但 c# 说这是一个无效的表达式?
  • @lost9123193 - 请展示您尝试过的内容。另请参阅有关 C# 7.0 的说明
  • 啊,我明白了,我使用的是 .net 4.5 而不是这个版本的 C#,我会尝试使用旧的方法看看它是否有效!
  • @lost9123193 - 你可以创建List&lt;Tuple&lt;string,List&lt;string&gt;&gt;&gt; 然后填充。以及用Tuple.Create(a,b)替换(..)的linq
  • 哇,那个字典初始化语法让我大吃一惊。我只熟悉{ { key, value}, {key2, value2}, /*...*/ }版本...
【解决方案2】:

如果您不想使用其他方式来存储数据并将它们存储在带有动物物种键的字典中,我建议您将与每个键关联的值的类型更改为 HashSet

Dictionary<string, HashSet<string>>

这样做,您可以遍历字典的键(O(n),其中 n 是键的数量)并使用 O(1) 中的 HashSet Contains 方法,您可以找出动物是否与当前关键/片段与否。

【讨论】:

    【解决方案3】:

    使用现有的字典结构,您可以这样做:

    string cheetahGroup = map.FirstOrDefault(item => 
        item.Value.Contains("cheetah", StringComparer.OrdinalIgnoreCase)).Key;
    

    请注意,如果动物不存在,则cheetahGroup 将是null。在上述情况下,它将是"Cat"

    【讨论】:

      【解决方案4】:

      正如其他人所建议的那样,我认为您应该在这里使用类。但其他响应停止在 1 个级别的类。我会推荐一种更全面的面向对象的方法。

      public abstract class Animal {}
      
      public abstract class Dog : Animal {}
      public abstract class Cat : Animal {}
      public abstract class Bird : Animal {}
      
      public sealed class Budgie : Bird {}
      public sealed class Parrot : Bird {}
      public sealed class Pitbull : Dog {}
      public sealed class Labrador : Dog {}
      public sealed class Cheetah : Cat {}
      public sealed class Lion : Cat {}
      

      [注意这里的密封是可选的]

      那你就说

      Labrador spot = new Labrador();
      

      检查是否是狗

      if (spot is Dog) {
          print("it's a dog");
      }
      

      此解决方案具有易于扩展和超级易于阅读的选项。没有什么奇怪的代码会让你分心,拉布拉多是狗,而鹦鹉是鸟。很清楚您要做什么以及 Dog、Cat、Cheetah 等代表什么类。

      如果您进一步想将拉布拉多分为巧克力、黄色和黑色,您可以添加另一层继承自拉布拉多的类。如果您需要定义动物的属性,那也很容易。例如,如果您只希望 Dogs 和 Cats 有名字,您可以在它们的类中添加一个 name 字段,而如果您希望所有动物都有一个名字,您可以将 name 字段放在 Animal 类中。

      如果您需要移动动物,您可以在动物级别定义一个名为 Move() 的方法,该方法强制其子级以自己的方式覆盖此方法,因此狗可能会通过 Walking() 进行 Move(),而小鸟会通过 Flying() 来 Move()。

      我会认真建议放弃字典并考虑使用类似于我描述的内容。如果您开始这样思考,它将真正帮助您计划更复杂的项目和任务。面向对象编程如此普及是有原因的!

      【讨论】:

        【解决方案5】:

        我会创建一个课程Animal,因为您正在与动物打交道,这将有两个属性:SpeciesSubSpecies

        public class Animal
        {
            public string Species { get; set; }
            public string SubSpecies { get; set; }
        
            public Animal(string Species, string SubSpecies)
            {
                this.Species = Species;
                this.SubSpecies = SubSpecies;
            }
        }
        

        然后你可以在一个列表中实例化你所有的动物:

        List<Animal> myAnimals = new List<Animal>();
        myAnimals.Add(new Animal("Bird", "Budgie"));
        myAnimals.Add(new Animal("Bird", "Parrot"));
        myAnimals.Add(new Animal("Dog", "Pitbull"));
        myAnimals.Add(new Animal("Dog", "Labrador"));
        myAnimals.Add(new Animal("Cat", "Cheetah"));
        myAnimals.Add(new Animal("Cat", "Lion"));    
        

        最后,您可以使用 Linq 找到您要查找的任何内容:

        //Will return null if the subSpecies doesn't exist
        public string FindTheSpecies(string SubSpecies)
        {
            return myAnimals.FirstOrDefault(x => x.SubSpecies == SubSpecies)?.Species;
        }
        

        【讨论】:

          猜你喜欢
          • 2014-12-07
          • 1970-01-01
          • 2011-01-09
          • 2020-04-08
          • 2022-12-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多