【问题标题】:Logical OR on two lists of boolean两个布尔值列表上的逻辑或
【发布时间】:2020-04-05 02:47:58
【问题描述】:

我有两个bool 列表,它们的长度总是相同的。假设这是我的两个列表:

var list1 = new List<bool>() { true, false, true, false, false };
var list2 = new List<bool>() { true, true, true, false, true };

我想通过将逻辑 OR 运算符应用于任一列表上的每个相应索引来创建一个新列表。所以,如果我的两个列表是上面的,我的预期结果将如下。

真、真、真、假、真

现在,我可以使用这样的for 循环轻松地做到这一点:

var result = new List<bool>();
for (int i = 0; i < list1.Count; i++)
{
    result.Add(list1[i] || list2[i]);
}

这非常有效,甚至不一定是低效的。但在我的应用程序中,我有超过 2 个列表,有时甚至 20 个,我需要获取所有列表中的 OR。

考虑到所有列表,有没有更简单的方法?

【问题讨论】:

  • 你知道.Zip()吗?
  • @gunr2171 不是真的。让我查一下。
  • 尝试同步相同长度的列表通常是primitive obsession 的症状,可以通过创建包含数据的类来解决。像两个值的逻辑或这样的属性可以是类属性。
  • @DourHighArch,这些列表实际上是一个类的属性。我正在开发一个带有数据网格的 WPF 应用程序,我根据这些列表的内容显示/隐藏列。数据网格显示文件的内容,由于不知道用户会选择哪些文件,所以不知道会有多少列。

标签: c# list linq boolean logical-operators


【解决方案1】:

在评论 Pavel Anikhouski 的回答时,您提到了多个列表。我将使用 Aggregate 扩展方法扩展该答案。

public static IEnumerable<bool> OrBooleanSequences(IEnumerable<IEnumerable<bool>> source)
{
    return source.Aggregate((a, b) => a.Zip(b, (x, y) => x || y));
}

只需将列表作为数组或其他可枚举对象传递,然后具体化结果。

var list1 = new List<bool>() { true, false, true, false, false, false };
var list2 = new List<bool>() { true, true, true, false, true, false };
var list3 = new List<bool>() { false, true, false, true, true, false };

var result = ZipMultiple(new[] { list1, list2, list3 }).ToList();

编辑

根据@Theodor Zoulias 的建议,我已将上述方法重命名。我选择了OrBooleanSequences。不过,这个名字是相当随意的,所以如果你使用它并且你想给它命名一个对你更有意义的名字,对你来说更有力量。

因此,这导致了一个更通用的方法,我将其称为 AggregateSequences,它将是一个高阶函数,采用描述如何执行聚合的函数(resultSelector 此处和 @987654327 @重载)。

public static IEnumerable<TSource> AggregateSequences<TSource>(IEnumerable<IEnumerable<TSource>> source, Func<TSource, TSource, TSource> resultSelector)
{
    return source.Aggregate((a, b) => a.Zip(b, resultSelector));
}

...您可以将逻辑 OR 操作作为 lambda 传递给它。

var result = AggregateSequences(new[] { list1, list2, list3 }, (x, y) => x || y).ToList();

这可以用于其他操作,例如对列表中的元素求和:

var list1 = new List<int>() { 1, 2, 3 };
var list2 = new List<int>() { 4, 5, 6 };
var list3 = new List<int>() { 7, 8, 9 };

var result = AggregateSequences(new[] { list1, list2, list3 }, (x, y) => x + y).ToList();

结果:

[ 12, 15, 18 ]

当然,这种方法只是一种变体。 Zip 和 Aggregate 有多个可以组合的重载。我不确定所有组合都有意义,但我会将其作为练习留给读者。

【讨论】:

  • 完美,这正是我想要的。
  • @gunr2171,我想大概是 20 多岁。哈哈。
  • 你可以用“或”作为组件来命名它,而不是ZipMultiple。甚至只是Or。
  • @TheodorZoulias:这是有道理的。让我考虑一下。听起来很适合高阶函数。
  • @TheodorZoulias:让我知道你对编辑的看法。
【解决方案2】:

你可以试试IEnumerable.Zip

var result = list1.Zip(list2, (first, second) => first || second);

它通过对来自两个源序列的每对元素应用逻辑或来生成结果序列。

【讨论】:

  • 如何将其扩展到 3 个或更多列表?假设我有 5 个甚至 20 个?
  • @Sach IMO,在这种情况下,常规循环将更具可读性:) 但让我考虑一下
  • 我想出了这个var result = (list1.Zip(list2, (first, second) =&gt; first || second)).Zip(list3, (first, second) =&gt; first || second);,我猜它对 3 来说是最好的,但除此之外,它看起来确实很旧 for 循环实际上会更容易理解。
【解决方案3】:

假设您有一个列表列表:

var listsOfLists = new List<IEnumerable<bool>>
{
    new List<bool>() { true, false, true, false, false },
    new List<bool>() { true, true, true, false, true },
    new List<bool>() { true, false, true, false, false },
    new List<bool>() { true, false, true, true, true }
};

使用 Linq,您可以使用 Aggregate 和 Zip 的组合

var combinedResults = listsOfLists
    .Aggregate((a, b) => a
        .Zip(b, (aElement, bElement) => aElement || bElement)
     );

Zip 将对两个选定列表中的每个元素进行配对,并对这些元素对运行“或”运算符,从而为您提供一个新的布尔列表。该结果列表将用于下一个聚合操作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多