Lambda表达式或Linq从列表中获取keyvaluepair的过滤结果?

时间:2015-07-01 04:29:04

标签: c# linq

我不知道如何编写表达式/查询来从包含IList<ITaskData> taskDataList //1st Level 的2级深度列表中获取结果

例如:

IList

此处ITaskData包含ITaskDataIList<KeyValuePair<object, object>> TaskParams { get; set; } //2nd Level 包含

的集合
TaskData

因此假设TaskParams具有低于键值对

关键:位置
价值观:Stockroom,Salesfloor

关键:迭代
值:1,2

因此,我需要获取包含TaskParams值库房和{1}的taskDataListType1列表。

我可以通过foreach循环轻松完成,但我想使用Linq / Lambda,它是一个衬垫,更容易维护。

非常感谢您的支持。如果您需要更多说明,请告诉我。

This is the structure of TaskData

foreach循环的工作代码:我在 IList<ITaskData> taskDataListType1 = new List<ITaskData>(); IList<KeyValuePair<object, object>> taskParams = null; bool iteration = false; bool location = false; foreach (ITaskData taskData in taskDataList) { taskParams = taskData.TaskParams; if (taskParams != null) { foreach (KeyValuePair<object, object> keyValuePair in taskParams) { if (keyValuePair.Key.ToString().Equals("ITERATION", StringComparison.OrdinalIgnoreCase)) { if (int.Parse(keyValuePair.Value.ToString()) == 1) { iteration = true; } } else if (keyValuePair.Key.ToString().Equals("LOCATION", StringComparison.OrdinalIgnoreCase)) { if (keyValuePair.Value.ToString() == "StockRoom") { location = true; } } if (iteration == true && location == true) { taskDataListType1.Add(taskData); } } } }

中得到了欲望输出
    IList<ITaskData> taskDataListType1 = new List<ITaskData>();

    foreach (TaskData td in taskDataList)
    {
                var tasks1 = taskParams.Where(kvp => kvp.Key != null
                                                && kvp.Value != null
                                                && kvp.Key.ToString().Equals("LOCATION", StringComparison.OrdinalIgnoreCase)
                                                 && kvp.Value.ToString() == "StockRoom"
                                                && kvp.Key.ToString().Equals("ITERATION", StringComparison.OrdinalIgnoreCase)
                                                && int.Parse(kvp.Value.ToString()) == 1
                                                );
    }

奇怪但是如果我把它放在逻辑之下它不起作用我的意思是我没有在tasks1中获得任何值

requestAlwaysAuthorization

以上截图的输出截图如下: enter image description here

4 个答案:

答案 0 :(得分:1)

如果您坚持在object中使用KeyValuePair,那么您的示例将如下所示:

IList<ITaskData> taskDataList = new List<ITaskData> 
{
    new ITaskData
    {
        TaskParams = new List<KeyValuePair<object,object>>
        {
            new KeyValuePair<object, object>("Location", "Stockroom"),
            new KeyValuePair<object, object>("Location", "Salesfloor"),
            new KeyValuePair<object, object>("Iteration", 1),
            new KeyValuePair<object, object>("Iteration", 2)
        }
    },
    new ITaskData
    {
        TaskParams = new List<KeyValuePair<object,object>>
        {
            new KeyValuePair<object, object>("Location", "Stockroom"),
            new KeyValuePair<object, object>("Location", "Salesfloor"),
            new KeyValuePair<object, object>("Iteration", 101),
            new KeyValuePair<object, object>("Iteration", 2)
        }
    }
};
var result = taskDataList.Where(td => 
    td.TaskParams.Any(tp => ((string)tp.Key == "Location") && ((string)tp.Value == "Stockroom")) &&
    td.TaskParams.Any(tp => (string)tp.Key == "Iteration" && (int)tp.Value == 1)
    );

正如您所看到的,您需要将object强制转换为精确类型,因此这种方法非常容易出错,如果您键入,很容易导致运行时异常,值集合将包含类型的项目与你的期望不同。

如果您需要按位置或迭代进行过滤,请在TaskParams类中将它们定义为属性,然后您的查询将变得更清晰,强类型且更不容易出错。请参阅以下示例:

public class TaskParamsType
{
    public IList<string> Locations;
    public IList<int> Iterations;
}

public class ITaskDataNew 
{
    public TaskParamsType TaskParams { get; set; } 
}

var result = taskDataList.Where(td => 
    td.TaskParams.Locations.Contains("Stockroom") &&
    td.TaskParams.Iterations.Contains(1)
    );

答案 1 :(得分:0)

试试这个:

var results =
    taskDataList
        .Where(td => td.TaskParams != null)
        .Where(td =>
            td.TaskParams.Any(kvp =>
                kvp.Key != null
                    && kvp.Key.ToString().Equals("LOCATION", StringComparison.OrdinalIgnoreCase)
                    && kvp.Value != null
                    && kvp.Value.Equals("Stockroom"))
            && td.TaskParams.Any(kvp =>
                kvp.Key != null
                    && kvp.Key.ToString().Equals("ITERATION", StringComparison.OrdinalIgnoreCase)
                    && kvp.Value != null
                    && kvp.Value.Equals(1)))
        .ToList();

我已针对此数据测试了此代码:

IList<ITaskData> taskDataList = new List<ITaskData>();

var taskData = new TaskData();
taskData.TaskParams.Add(new KeyValuePair<object, object>("Location", "Stockroom"));
taskData.TaskParams.Add(new KeyValuePair<object, object>("Location", "Salesfloor"));
taskData.TaskParams.Add(new KeyValuePair<object, object>("Iteration", 1));
taskData.TaskParams.Add(new KeyValuePair<object, object>("Iteration", 2));
taskDataList.Add(taskData);

答案 2 :(得分:-1)

它应该是这样的:

var tasks = taskDataList.Where(
    i => i.TaskParams.Any(x => x.Key == "Location" && x.Value.Contains("Stockroom")) &&
         i.TaskParams.Any(x => x.Key == "Iteration" && x.Values.Contains(2)));

上面的代码只是为了解释逻辑。您需要将对象转换为正确的类型(如果您了解它们)或使用其他比较方法。

答案 3 :(得分:-1)

假设您有以下代码返回符合逻辑条件的List<KeyValuePair<object, object>>

public class ITaskData
{
    public List<KeyValuePair<object, object>> keyValuePairs { get; set; }
}

class Program
{
    private static List<ITaskData> list = new List<ITaskData>();

    private static void Main()
    {
        List<KeyValuePair<object, object>> result = new List<KeyValuePair<object, object>>();

        foreach (var a in list)
            foreach (var b in a.keyValuePairs)
                if (b.Value.ToString().Contains("Stockroom")) result.Add(b); 
                // Here I make .ToString().Contains("Stockroom")
                // You can add any required logics here
    }
}

你可以在LINQ中创建:

List<KeyValuePair<object, object>> result = 
    (from a in list 
     from b in a.keyValuePairs 
     where b.Value.ToString().Contains("Stockroom") 
     select b)
    .ToList();

或者在LINQ方法链中:

List<KeyValuePair<object, object>> result = 
    (list
        .SelectMany(a => a.keyValuePairs, (a, b) => new {a, b})
        .Where(t => t.b.Value.ToString().Contains("Stockroom"))
        .Select(t => t.b)
    ).ToList();

但是,以我的私人观点,在您的情况下,foreach的解决方案看起来更优雅和可读。
当然,此代码将抛出NullReferenceException,因为keyValuePairs未初始化。我没有初始化它,因为它是一个示例,并且您有自己的ITaskData类并且具有正确的初始化。