通用LINQ函数 - 选择Func作为参数的SelectMany

时间:2009-09-03 22:36:27

标签: c# linq-to-objects

我有一个包含许多字符串数组的类。我想要一个通用函数,它可以为给定属性提供一个唯一的List<string>。例如:

public class Zoo 
{    
  string Name { get; set;}
  string[] Animals { get; set;}
  string[] Zookeepers { get; set;}
  string[] Vendors { get; set;}
}

我想要一个通用函数,它会在列表中为我提供一个独特的List<string>动物?我希望这是通用的,所以我也可以得到一个明确的Zookeepers和供应商列表。

我一直在尝试这个,但它没有编译:

public static List<string> GetExtendedList(Func<Zoo, string[]> filter)
{
        var Zoos = QueryZoos(HttpContext.Current);
        return Zoos.Where(z => z.Type == "Active")
            .SelectMany(filter)
            .Distinct()
            .OrderBy(s => s);
    }

注意:这与我之前提出的两个问题有关,但我在合并信息时遇到了问题。我之前曾问how to query using SelectMany (SO 1229897)并单独询问如何编写gets a list using Select rather than SelectMany (SO 1278989)

的通用函数

3 个答案:

答案 0 :(得分:19)

  

“每个动物园”

点击

假设您有一个动物园列表:

List<Zoo> zooList = GetZooList();

然后,如果您想要来自所有动物园的不同动物,您将以这种方式应用SelectMany:

List<string> animalList = zooList
  .SelectMany(zoo => zoo.animals)
  .Distinct()
  .ToList();

如果您经常执行此任务并希望使用一个函数来包装这三个调用,则可以这样编写这样的函数:

public static List<string> GetDistinctStringList<T>(
  this IEnumerable<T> source,
  Func<T, IEnumerable<string>> childCollectionFunc
)
{
  return source.SelectMany(childCollectionFunc).Distinct().ToList();
}

然后会被称为:

List<string> animals = ZooList.GetDistinctStringList(zoo => zoo.animals);

对于未编译的代码示例(您没有给出错误消息),我推断您需要添加ToList():

.OrderBy(s => s).ToList();

另一个问题(无法推断出类型参数的原因)是string[]没有实现IEnumerable<string>。将该类型参数更改为IEnumerable<string>而不是string[]

答案 1 :(得分:1)

最好的方法是为每个String[]创建HashSet<String> - 这会过滤掉所有重复项。

由于HashSet<T>有一个接受IEnumerable<T>的构造函数,你可以通过将每个数组传递给构造函数来简单地实例化HashSet<T>。生成的HashSet<T>将是Strings的不同列表。虽然这不是您所要求的List<String>,但HashSet<T> 确实实施ICollection<T>,因此您需要的许多方法都可用。

static ICollection<String> GetDistinct(IEnumerable<String> sequence)
{
    return new HashSet<String>(sequence);
}

答案 2 :(得分:1)

也许我错过了你的意思,但只是......

List<String> distinctAnimals = zoo.Animals.Distinct().ToList();

会按照你的要求做,我认为你的意思是其他的吗?

编辑: 如果你有一个动物园列表,但想要不同的动物,那么选择很多是正确的事情,IMO使用linq声明语法更容易......

List<String> animals = (from z in zoos
                       from s in z.Animals
                       select s).Distinct().ToList();