在C#中从字典过滤键值

时间:2017-12-05 20:04:59

标签: c# dictionary filter

我是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"})

};

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

5 个答案:

答案 0 :(得分:1)

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

Dictionary<string, HashSet<string>>

这样做可以遍历字典中的键(O(n),其中n是键的数量),并使用Contains中的HashSet O(1)方法,您可以查看是否动物与当前的关键词/ spiece相关联。

答案 1 :(得分:1)

更好的数据建模将是创建一个组的类,其中包含一个名称和一组动物。然后,您可以保存一组组并进行查询。

如果你想坚持使用字典,那么:正如你的问题是从该键的值列表中检索给定key的{​​{1}},我将组织数据其他方式:

value

然后你可以用真正的钥匙搜索 - 这是物种而不是群体:

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

通过分组到物种列表来构建数据更容易:

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

这适用于名为元组的C#7.0。如果您使用的是以前的版本,则可以使用匿名类型或“旧时尚”元组

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

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);

答案 2 :(得分:1)

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

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

请注意,如果动物不存在,则cheetahGroup将为null。在上面的情况中,它将是"Cat"

答案 3 :(得分:0)

正如其他人所说,我认为你应该在这里使用课程。但其他反应停在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拥有名称,则可以在其类中添加名称字段,而如果您希望所有动物都有名称,则可以将名称字段放在Animal类中。

如果您需要移动动物,您可以在动物级别定义一个名为Move()的方法,强制其子项以自己的方式覆盖此方法,因此也许狗会通过Walking()移动(),而鸟类将飞行()飞行()。

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

答案 4 :(得分:0)

我会创建一个课程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;
}