Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/337.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 是否有一种方法可以使用LINQ根据封闭条件(即不是简单的WHERE子句)选择一系列项?_C#_Linq_Lambda - Fatal编程技术网

C# 是否有一种方法可以使用LINQ根据封闭条件(即不是简单的WHERE子句)选择一系列项?

C# 是否有一种方法可以使用LINQ根据封闭条件(即不是简单的WHERE子句)选择一系列项?,c#,linq,lambda,C#,Linq,Lambda,假设您有一个对象的列表,并且Foo有一个IsSelected属性,比如 public class Foo { public string Name{ get; set; } public bool IsSelected{ get; set; } } List<Foo> sourceItems = new List<Foo> { new Foo(){ Name="First", IsSelected=false}, new Foo(){

假设您有一个对象的
列表
,并且
Foo
有一个
IsSelected
属性,比如

public class Foo
{
    public string Name{ get; set; }
    public bool IsSelected{ get; set; }
}

List<Foo> sourceItems = new List<Foo>
{
    new Foo(){ Name="First",   IsSelected=false},
    new Foo(){ Name="Second",  IsSelected=true },
    new Foo(){ Name="Third",   IsSelected=false},
    new Foo(){ Name="Fourth",  IsSelected=true },
    new Foo(){ Name="Fifth",   IsSelected=false},
    new Foo(){ Name="Sixth",   IsSelected=true },
    new Foo(){ Name="Seventh", IsSelected=true },
    new Foo(){ Name="Eighth",  IsSelected=false},
    new Foo(){ Name="Ninth",   IsSelected=false},
    new Foo(){ Name="Tenth",   IsSelected=false}
};
var results = sourceItems.Where(item => item.IsSelected);
…但是如果我想要第一个项目和最后一个项目之间的所有项目,其中IsSelected为true,该怎么办?(即第二次到第七次)

我知道我可以使用SkipWhile,因为它会一直跳到第一个true语句,然后返回后面的所有内容

// Returns from Second on
var results = sourceItems.SkipWhile(item => !item.IsSelected);
…我知道我可以倒车,然后再做同样的事情,但最后我不得不重新倒车,而重复倒车感觉成本太高了

我的另一个想法是使用Select with索引并将最后一个索引存储在ISSELECT为true的位置,然后在末尾使用where子句,检查该索引是否低于最后一个选定的索引,但这看起来既昂贵又笨拙

int lastSelectedIndex = -1;
var results = sourceItems
    .SkipWhile(item => !item.IsSelected)
    .Select( (item, itemIndex) => 
    {
        if(item.IsSelected)
            lastSelectedIndex = index;

        return new {item, index};
    })
    .Where(anonObj => anonObj.index <= lastSelectedIndex)
    .Select(anonObj => anonObj.Item);

那么有没有其他方法来实现我的要求呢?

您可以在Where中传递索引,并在条件中使用它

var result = sourceItems.Where((ele, index) => 
             index > 0 && index < 7 && ele.IsSelected);

你最初的直觉是对的。请这样做:

var results =
    sourceItems
        .SkipWhile(x => x.IsSelected == false)
        .Reverse()
        .SkipWhile(x => x.IsSelected == false)
        .Reverse();
除非您的列表包含数百万项,否则它不会有太大的性能问题


我刚刚用列表中的1000000个元素尝试了这段代码,它在我三岁的笔记本电脑上用163毫秒就完成了。10000000只花了1.949秒。

您可以使用
.Aggregte
执行此操作,并且只迭代一次,但有点混乱:

var lists = sourceItems.Aggregate(Tuple.Create(new List<Foo>(), new List<Foo>()), (acc, foo) =>
{
    if (foo.IsSelected)
    {
        acc.Item1.AddRange(acc.Item2);
        acc.Item2.Clear();
        acc.Item2.Add(foo);
    }
    else if (acc.Item2.Any())
    {
        acc.Item2.Add(foo);
    }
    return acc;
});

if (lists.Item2.Any()) lists.Item1.Add(lists.Item2.First());

您甚至可以将其更改为返回另一个列表,并将
yield
s替换为
List。如果需要,请添加

好吧,让我通过使用索引和将项目添加到新集合来不同地处理此问题

List<Foo> sourceItems = new List<Foo>
{
    new Foo(){ Name="First",   IsSelected=false},
    new Foo(){ Name="Second",  IsSelected=true },
    new Foo(){ Name="Third",   IsSelected=false},
    new Foo(){ Name="Fourth",  IsSelected=true },
    new Foo(){ Name="Fifth",   IsSelected=false},
    new Foo(){ Name="Sixth",   IsSelected=true },
    new Foo(){ Name="Seventh", IsSelected=true },
    new Foo(){ Name="Eighth",  IsSelected=false},
    new Foo(){ Name="Ninth",   IsSelected=false},
    new Foo(){ Name="Tenth",   IsSelected=false}
};

int startIndex = sourceItems.FindIndex(x => x.IsSelected);
int endIndex   = sourceItems.FindLastIndex(x => x.IsSelected);

var items = new List<Foo>();

for (int i = startIndex; i <= endIndex; i++)
    items.Add(sourceItems[i]);    
List sourceItems=新列表
{
new Foo(){Name=“First”,IsSelected=false},
new Foo(){Name=“Second”,IsSelected=true},
new Foo(){Name=“Third”,IsSelected=false},
new Foo(){Name=“Fourth”,IsSelected=true},
new Foo(){Name=“Fifth”,IsSelected=false},
new Foo(){Name=“Sixth”,IsSelected=true},
new Foo(){Name=“Seventh”,IsSelected=true},
new Foo(){Name=“第八”,IsSelected=false},
new Foo(){Name=“nixth”,IsSelected=false},
new Foo(){Name=“Tenth”,IsSelected=false}
};
int startIndex=sourceItems.FindIndex(x=>x.IsSelected);
int endIndex=sourceItems.FindLastIndex(x=>x.IsSelected);
var items=新列表();

对于(inti=startIndex;i以及Dimi Toulakis

如果有人经常在他的代码中需要它,这里有一个扩展

public static class ListExtension
{
    public static List<T> FindGroup<T>(this List<T> mylist, Predicate<T> pred)
    {
        var first = mylist.FindIndex(pred);
        var last = mylist.FindLastIndex(pred);
        last += 1; // to get the Last Element

        return mylist.GetRange(first, last - first);
    }
}
公共静态类ListExtension
{
公共静态列表FindGroup(此列表mylist,谓词pred)
{
var first=mylist.FindIndex(pred);
var last=mylist.findlastinex(pred);
last+=1;//获取最后一个元素
返回mylist.GetRange(first,last-first);
}
}
组合和:

List sourceItems=新列表{
new Foo(){Name=“First”,IsSelected=false},
new Foo(){Name=“Second”,IsSelected=true},
new Foo(){Name=“Third”,IsSelected=false},
new Foo(){Name=“Fourth”,IsSelected=true},
new Foo(){Name=“Fifth”,IsSelected=false},
new Foo(){Name=“Sixth”,IsSelected=true},
new Foo(){Name=“Seventh”,IsSelected=true},
new Foo(){Name=“第八”,IsSelected=false},
new Foo(){Name=“nixth”,IsSelected=false},
new Foo(){Name=“Tenth”,IsSelected=false}
};
int startIndex=sourceItems.FindIndex(item=>item.IsSelected);
int endIndex=sourceItems.findlastedex(item=>item.IsSelected);

var result=sourceItems。其中((item,itemIndex)=>itemIndex>=startIndex&&itemIndex这是一个追逐性能并不总是有效的好例子。此解决方案产生正确的结果,但比“双反转”慢方法。我花了2.267秒来处理10000000个项目的列表,相比之下,使用双反转方法需要1.949秒。@Enigmativity如果您想要性能,那么LINQ不是最好的方法-只需一直使用命令行即可(请参阅我的编辑)哦,是的,我完全同意你的观点。我的观点是,只有当列表中有数百万个对象时,性能才会成为一个问题。因此,使用最简单的LINQ通常是一种方法。命令式几乎总是更快,但更难维护。你可以一直走到极端,在汇编程序中编写代码-这是最快的-但我t不可维护。99.9%的时间使用简单LINQ。@卡斯滕,你的编辑看起来很有趣,但我在跟踪双收益回报率方面有点困难,特别是在最初的一眼中,它似乎是按相反的顺序返回的。你也有Jyield
将返回带有
IsSelected
标志的元素-之前的循环将生成从最后一个
IsSelected
-元素(
lastSelected=i+1
)之后到当前(
j
)之前的所有元素-如果你试着像
j Dude那样做…谢谢,但这有点离题。这是我从脑海中键入的伪代码,用来显示我们的问题,不是实际代码。尽管如此,我还是做了更改。而且,你的答案似乎没有解决我在这里要找的问题,因为我不确定你从哪里得到了0和7。我从OP中得到了0和7(即第二次到第七次),需要哪些元素?是否要先排除第一个和最后一个,然后检查哪些对象的IsSelected=true,或者首先要筛选IsSelected=true的所有对象,然后排除第一个和最后一个?否,范围基于IsSelected设置为true的第一个和最后一个项目。如我的问题详细信息所述,我正在查找g第一个和最后一个选择的项目之间的项目范围,无论是否也选择了中间的项目。希望有意义。检查我的更新,我认为这将为您提供所需的输出,但我不确定效率如何
static IEnumerable<Foo> BetweenSelected(List<Foo> foos)
{
    var lastSelected = foos.Count;

    for (var i = 0; i < foos.Count; i++)
    {
        var foo = foos[i];
        if (foo.IsSelected)
        {
            for (var j = lastSelected; j < i; j++)
                yield return foos[j];
            lastSelected = i+1;
            yield return foo;
        }
    }
}
List<Foo> sourceItems = new List<Foo>
{
    new Foo(){ Name="First",   IsSelected=false},
    new Foo(){ Name="Second",  IsSelected=true },
    new Foo(){ Name="Third",   IsSelected=false},
    new Foo(){ Name="Fourth",  IsSelected=true },
    new Foo(){ Name="Fifth",   IsSelected=false},
    new Foo(){ Name="Sixth",   IsSelected=true },
    new Foo(){ Name="Seventh", IsSelected=true },
    new Foo(){ Name="Eighth",  IsSelected=false},
    new Foo(){ Name="Ninth",   IsSelected=false},
    new Foo(){ Name="Tenth",   IsSelected=false}
};

int startIndex = sourceItems.FindIndex(x => x.IsSelected);
int endIndex   = sourceItems.FindLastIndex(x => x.IsSelected);

var items = new List<Foo>();

for (int i = startIndex; i <= endIndex; i++)
    items.Add(sourceItems[i]);    
public static class ListExtension
{
    public static List<T> FindGroup<T>(this List<T> mylist, Predicate<T> pred)
    {
        var first = mylist.FindIndex(pred);
        var last = mylist.FindLastIndex(pred);
        last += 1; // to get the Last Element

        return mylist.GetRange(first, last - first);
    }
}
List<Foo> sourceItems = new List<Foo>{
    new Foo(){ Name="First",   IsSelected=false},
    new Foo(){ Name="Second",  IsSelected=true },
    new Foo(){ Name="Third",   IsSelected=false},
    new Foo(){ Name="Fourth",  IsSelected=true },
    new Foo(){ Name="Fifth",   IsSelected=false},
    new Foo(){ Name="Sixth",   IsSelected=true },
    new Foo(){ Name="Seventh", IsSelected=true },
    new Foo(){ Name="Eighth",  IsSelected=false},
    new Foo(){ Name="Ninth",   IsSelected=false},
    new Foo(){ Name="Tenth",   IsSelected=false}
};

int startIndex = sourceItems.FindIndex(item => item.IsSelected);
int endIndex   = sourceItems.FindLastIndex(item => item.IsSelected);

var result = sourceItems.Where((item, itemIndex) => itemIndex >= startIndex && itemIndex <= endIndex);
int endIndex = sourceItems.FindLastIndex(item => item.IsSelected);

var result = sourceItems
    .TakeWhile((item, itemIndex) => itemIndex <= endIndex) // Take all before (and including) index of last match (must be before SkipWhile as that would change the index)
    .SkipWhile(item => !item.IsSelected); // Skip up until the first item where IsSelected is true