使用LINQ从列表列表中返回选择对象和仅所需的子值

问题描述

对于这个看似简单的LINQ问题,我找不到解决方案。

我正在尝试返回对象列表,其中每个对象在属性子列表中都具有特定值。我需要返回对象,仅返回那些子列表值

例如:

我的课程简化了:

public class Fruit()
{
   public List<keyvaluePairs> items {get;set;)
}
public class keyvaluePair()
{
   public string Key {get;set;}
   public string Value {get;set;}
}

我的水果清单:

fruitList = new List<Fruit>(){Fruit1,Fruit2,Fruit3,Fruit4}


Fruit1.items = {name: apple,color: red}
Fruit2.items = {name: apple,color: green}
Fruit3.items = {name: apple,date: 2020}
Fruit4.items = {name: grape,color: green}

仅返回子列表中带有“颜色”的水果,并且仅返回其子列表中的“颜色”键/值。因此结果看起来像:

Fruit1.items = {color: red}
Fruit2.items = {color: green}
Fruit4.items = {color: green}

感谢您的帮助!

解决方法

使用Linq似乎是最好的主意。

var result = from fruit in fruitList
             where fruit.items.Any(i => i.Key == "color")
             select new {Color = fruit.items.First(i => i.Key == "color").Value};

这将返回匿名类型。

,

显然,您的#ifndef HASHING_H #define HASHING_H /* If we are we on Windows,we want a single define for it.*/ #if !defined(_WIN32) && (defined(__WIN32__) || defined(WIN32) || defined(__MINGW32__)) #define _WIN32 #endif /* _WIN32 */ #if defined(_WIN32) && defined(_HASHING_BUILD_DLL) /* We are building Hashing as a Win32 DLL */ #define HASHING_API __declspec(dllexport) #elif defined(_WIN32) && defined(HASHING_DLL) /* We are calling Hashing as a Win32 DLL */ #define HASHING_API __declspec(dllimport) #elif defined(__GNUC__) && defined(_HASHING_BUILD_DLL) /* We are building Hashing as a shared / dynamic library */ #define HASHING_API __attribute__((visibility("default"))) #else /* We are building or calling HASHING as a static library */ #define HASHING_API #endif //your inlcudes class HASHING_API MyClass { //... }; #endif // !HASHING_H 中的Key是唯一的。您没有两个带有Items“颜色”的KeyValuePairs

其他人给出的以下内容将起作用:

Key

但是,为此,您将多次扫描var result = from fruit in fruitList where fruit.items.Any(i => i.Key == "color") select new {Color = fruit.items.First(i => i.Key == "color").Value}; 的序列:一次以查看是否至少有一个Items的值为“ color”,丢弃结果,然后重新开始在第一个Key处,找到第一个Item为“颜色”的Item

当然可以提高效率:从每个Key中获取其数据及其第一个Fruit,且其中Item等于“颜色”或默认值,然后丢弃每个{ {1}}中没有这样的第一个Key

在您的(可能是简化的)示例中,水果只有项目。在这种情况下,它甚至可以更简单地完成。但首先让我们假设一个水果具有我想要的其他一些属性:

Fruit

这将获取您的第一个Fruit,并开始枚举Items,直到找到Key ==“ color”的第一个Fruit。它会记住该项目,ans会跳过其余项目。然后继续第二个水果的项目,依此类推,直到列举了所有水果为止。

因此,物品最多只能扫描一次。找到某个水果的合适项目后,将不扫描该水果的其余项目。

,

不保留对象实际实例的解决方案:

fruitList.Where(f => f.items.Any(i => i.Key == "color")).Select(f => new Fruit { items = f.items.Where(i => i.Key == "color").ToList() });
,

这是使用Linq Select方法完成的,您在其中传递了lambda函数,该函数返回所需的内容。这在您想在返回对象之前传递对象的特定实现时非常有用。类似于以下内容:

fruitList.Where(x => x.Value == "red").Select(s =>
{
  return s.Value;
});

修改

.Select(s =>
                {
                    return s.items.Where(itm=>itm.Value.StartsWith("y"))
                    .Select(itm => { return itm.Value; }).ToList<string>();
    
                });
,

LINQ适合过滤和查询,但不适用于修改数据。由于您想更改原始对象以过滤items成员,因此需要在找到它们之后对其进行处理。

  1. 首先,使用LINQ获取适当的Fruit对象的列表:

    var ans = fruitList.Where(f => f.items.Any(kv => kv.Key == "color")).ToList();
    
  2. 将每个Fruit修改为仅具有所需的items成员:

    foreach (var fruit in ans)
        fruit.items = fruit.items.Where(kv => kv.Key == "color").ToList();
    // ans is original Fruit objects now with filtered items members