使用 if - else if 结构将 foreach 重构为 LINQ

发布于 2024-12-10 11:56:53 字数 1289 浏览 0 评论 0原文

我有这个 foreach 循环:

var includedElements = new HashSet<int>();
foreach(var e in elements)
{
    var include = false;
    if(isTable(e.Key))
    {
        if(tables.ContainsKey(e.Key)
        {
            if(tables[e.Key].Elements
               .Any(subElem => shouldBeIncluded(subElem.Key) ) )
            {
                include = true;
            }
        }
    }
    else if(shouldBeIncluded(e.Key))
    {
        include = true;
    }
    if(include){
        includedElements.Add(e.Key);
        DoSomeMoreStuff(e);
    }
}

我尝试将其重构为 LINQ:

var query = 
    from e in elements
    where 
    ( 
        isTable(e.Key)
        && tables.ContainsKey(e.Key)
        && tables[e.Key].Elements
                .Any(subElem => shouldBeIncluded(subElem.Key) )
    ) || (
        !isTable(e.Key)
        && shouldBeIncluded(e.Key)
    )
    select e;
foreach(e in query){
    includedElements.Add(e.Key);
    DoSomeMoreStuff(e);
}

我不确定的是这里的 or 子句。在我的脑海中,我需要包含 !isTable(e.Key) 来处理外部 if/else if 结构。
我的重构思路正确吗?这两个代码示例是否产生相同的逻辑功能?

这是一种我只需调用一次 isTable 就可以逃脱的方法吗?正如我现在所拥有的,我需要在 || 的另一侧将其称为倒置。

I have this foreach loop:

var includedElements = new HashSet<int>();
foreach(var e in elements)
{
    var include = false;
    if(isTable(e.Key))
    {
        if(tables.ContainsKey(e.Key)
        {
            if(tables[e.Key].Elements
               .Any(subElem => shouldBeIncluded(subElem.Key) ) )
            {
                include = true;
            }
        }
    }
    else if(shouldBeIncluded(e.Key))
    {
        include = true;
    }
    if(include){
        includedElements.Add(e.Key);
        DoSomeMoreStuff(e);
    }
}

I have tried to refactor this to LINQ:

var query = 
    from e in elements
    where 
    ( 
        isTable(e.Key)
        && tables.ContainsKey(e.Key)
        && tables[e.Key].Elements
                .Any(subElem => shouldBeIncluded(subElem.Key) )
    ) || (
        !isTable(e.Key)
        && shouldBeIncluded(e.Key)
    )
    select e;
foreach(e in query){
    includedElements.Add(e.Key);
    DoSomeMoreStuff(e);
}

What I'm not sure of is the or clause here. In my head I need to include !isTable(e.Key) to handle the outer if/else if structure.
Am I thinking right with my refactoring? Are these two code examples resulting in the same logical functionality?

Is it a way I can get away with only one call to isTable? As I have it now I need to call it inverted on the other side of the ||.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

青柠芒果 2024-12-17 11:56:53

是的你是对的。 if isTable 没有副作用(除了检查某些内容之外不执行任何操作)并且基于参数是确定性的(因此使用 e.Key 调用它两次总是会产生相同的值)。尽管如此,它可能(它可能是一个过早的优化......谁知道呢?)可能更好地保持它与原始if更加相似并使用三元运算符 (? :),这样就不必重新检查 isTable

var query = 
    from e in elements
    where 
        isTable(e.Key) ? 

            tables.ContainsKey(e.Key) && tables[e.Key].Elements
                .Any(subElem => shouldBeIncluded(subElem.Key) ) 
        :

            shouldBeIncluded(e.Key)
    select e;

我会补充一点,如果您讨厌三元运算符,您可以使用 let 关键字:

var query = 
    from e in elements
    let isT = isTable(e.Key)
    where 
        ( isT && tables.ContainsKey(e.Key) && tables[e.Key].Elements
            .Any(subElem => shouldBeIncluded(subElem.Key) ) )
            ||
        ( !isT && shouldBeIncluded(e.Key) )
    select e;

缓存 isTable(e.Key)

Yes you are right. This if isTable doesn't have side effects (doesn't do anything but check something) and is deterministic based on the parameters (so calling it twice with e.Key always result in the same value). Still it could (it could be a premature optimization... Who knows?) probably be better to keep it more similar to the original if and use a ternary operator (? :) so not to recheck isTable

var query = 
    from e in elements
    where 
        isTable(e.Key) ? 

            tables.ContainsKey(e.Key) && tables[e.Key].Elements
                .Any(subElem => shouldBeIncluded(subElem.Key) ) 
        :

            shouldBeIncluded(e.Key)
    select e;

I'll add that if you hate ternary operators, you could use the let keyword:

var query = 
    from e in elements
    let isT = isTable(e.Key)
    where 
        ( isT && tables.ContainsKey(e.Key) && tables[e.Key].Elements
            .Any(subElem => shouldBeIncluded(subElem.Key) ) )
            ||
        ( !isT && shouldBeIncluded(e.Key) )
    select e;

to cache the isTable(e.Key)

雨后咖啡店 2024-12-17 11:56:53

你是对的。 else if 暗示 if 条件不匹配,因此

if(A) { 
    if(B) { 
        if(C) { 
            include = true; 
        } 
    } 
}
else if(D) {
    include = true;
}

相当于

if(A) { 
    if(B) { 
        if(C) { 
            include = true; 
        } 
    } 
}

if(!A && D) {
    include = true;
}

which 相当于

if ((A && B && C) || (!A && D)) {
    include = true;
}

which 正是您在 LINQ 中编写的内容。

You are correct. The else if implies that the if condition did not match, so

if(A) { 
    if(B) { 
        if(C) { 
            include = true; 
        } 
    } 
}
else if(D) {
    include = true;
}

is equivalent to

if(A) { 
    if(B) { 
        if(C) { 
            include = true; 
        } 
    } 
}

if(!A && D) {
    include = true;
}

which is equivalent to

if ((A && B && C) || (!A && D)) {
    include = true;
}

which is exactly what you have written in LINQ.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文