如何使用 LINQ 从通用列表中获取下一个合适的值?
How can I get the next appropriate value from a generic list using LINQ?
我有一个 class:
public class CounselPoints
{
public int CounselNum { get; set; }
public String CounselPoint { get; set; }
public bool BR { get; set; }
public bool ICRVBS { get; set; }
}
...以及 class 的通用列表:
List<CounselPoints> counselPoints = AYttFMConstsAndUtils.DeserializeCounselPointsFile();
我想从通用列表中检索下一个合适的 CounselPoint,其逻辑可以用 SQL 表示,如下所示:
SELECT TOP 1 CounselNumber
FROM COUNSELPOINTSLU
WHERE BR IS TRUE
AND CounselNumber > @LastCounselPoint;
我调用此方法来尝试获取该值,并且像这样挥舞着它:
public static int GetNextBibleReadingCounselPoint(int LastCounselPoint)
{
List<CounselPoints> counselPoints = AYttFMConstsAndUtils.DeserializeCounselPointsFile();
return counselPoints.FirstOrDefault(i => i.CounselNum).Where(j => j.BR).Where(k => k.CounselNum > LastCounselPoint);
}
在 "English," 我想说的是,“给我第一个 CounselNum,它比传入的 arg (LastCounselPoint) 的数字更大,并且 BR 为真"
例如,如果我传入 17,并且 CounselNum val 为 18 的 counsePoint "record" 也将 BR 设置为 true,则它应该 return 18。很简单,不是吗?
但是我的尝试显然很丑陋,或者充其量是笨拙的,甚至没有编译;我得到:
错误 CS0029 无法将类型 'int' 隐式转换为 'bool'
...和:
错误 CS1662 无法将 lambda 表达式转换为预期的委托类型,因为块中的某些 return 类型无法隐式转换为委托 return 类型
我不知道为什么它认为我正在尝试转换为 bool,我绝对不会理解第二个错误。
如果我将代码更改为:
return counselPoints.FirstOrDefault(i => i.CounselNum > LastCounselPoint).Where(j => j.BR).Select(k => k.CounselNum );
我得到:
错误 CS1061 'CounselPoints' 不包含 'Where' 的定义并且没有扩展方法 'Where' 接受类型 'CounselPoints' 的第一个参数可以是找到(您是否缺少 using 指令或程序集引用?)
...这也只会导致我告诉编译器,“除了九点,其他都倒下了;把它们放在另一条胡同上。”
解开这个难题的关键是什么?
使用查询时,首先需要使用过滤条件,然后才调用FirstOrDefault
:
return counselPoints
.Where(j => j.BR)
.Where(k => k.CounselNum > LastCounselPoint)
.Select(i => i.CounselNum)
.FirstOrDefault();
有 2 种类型的 LINQ 查询运算符 - immediate and deferred。 Where
是延迟运算符的例子,FirstOrDefault
是立即运算符。
在您的代码中,您在无序列表上使用了 FirstOrDefault
,因此您立即过滤了初始列表。
在我提供的示例代码中,我首先使用延迟运算符定义过滤器,然后才使用即时函数检索结果。
试试这个....
counselPoints
.Where(j => j.BR && j.CounselNum > LastCounselPoint)
.FirstOrDefault();
我认为 dotnetom 和 Chris Moutray 已经回答了这个问题,我只想做一个小的旁注:
下次您遇到 LINQ 语句问题时,请尝试将它们拆分为单独的语句。这样做你会发现 FirstOrDefault()
在 Where() 之前没有任何意义,因为它会 return 一个单一的对象,你不能在单一对象上使用 where,对吗? :)
我在你的例子(以及其他答案)中看到你写的 first-default 是这样的:.FirstOrDefault(i => i.CounselNum)
但我认为你不需要这个。
将第一个默认值视为过滤器而不是 select。
所以你需要这样写
return counselPoints
.Where(cp => cp.BR && cp.CounselNum > LastCounselPoint) // where clause
.Select(cp => cp.CounselNum) // select part
.FirstOrDefault(); // get top 1 only
*更新 > 存在
正如@Jannik 指出的那样,当没有匹配项时,returns 为零而不是 null。
如果同时测试存在性很重要,那么你可以这样写。
CounselPoint cp = counselPoints
.Where(cp => cp.BR && cp.CounselNum > LastCounselPoint) // where clause
.FirstOrDefault(); // get top 1 object of type CounselPoint
if (cp == null)
return null;
return cp.CounselNum;
请注意,您的方法的 return 类型必须是可为 null 的 int。请参阅下面添加的 ?
。
public static int? GetNextBibleReadingCounselPoint(int LastCounselPoint)
...然后我猜你调用代码来检查结果
int? result = GetNextBibleReadingCounselPoint(lastCounselPoint);
if (result.HasValue) {
// something was returned
} else {
// nothing was returned
int num = result.Value;
}
*update2 > 订单
想着你的原创SQL - 不知道你是不是考虑下订单了??
也许你应该在底部添加一个订单:
SELECT TOP 1 CounselNumber
FROM COUNSELPOINTSLU
WHERE BR IS TRUE
AND CounselNumber > @LastCounselPoint
ORDER BY CounselNumber; // ascending
在这种情况下,您可以在 linq 语句中的 where 子句之前添加 order-by;像这样
return counselPoints
.OrderBy(cp => cp.CounselNum) // order by ascending
.Where( ... rest of code
我有一个 class:
public class CounselPoints
{
public int CounselNum { get; set; }
public String CounselPoint { get; set; }
public bool BR { get; set; }
public bool ICRVBS { get; set; }
}
...以及 class 的通用列表:
List<CounselPoints> counselPoints = AYttFMConstsAndUtils.DeserializeCounselPointsFile();
我想从通用列表中检索下一个合适的 CounselPoint,其逻辑可以用 SQL 表示,如下所示:
SELECT TOP 1 CounselNumber
FROM COUNSELPOINTSLU
WHERE BR IS TRUE
AND CounselNumber > @LastCounselPoint;
我调用此方法来尝试获取该值,并且像这样挥舞着它:
public static int GetNextBibleReadingCounselPoint(int LastCounselPoint)
{
List<CounselPoints> counselPoints = AYttFMConstsAndUtils.DeserializeCounselPointsFile();
return counselPoints.FirstOrDefault(i => i.CounselNum).Where(j => j.BR).Where(k => k.CounselNum > LastCounselPoint);
}
在 "English," 我想说的是,“给我第一个 CounselNum,它比传入的 arg (LastCounselPoint) 的数字更大,并且 BR 为真"
例如,如果我传入 17,并且 CounselNum val 为 18 的 counsePoint "record" 也将 BR 设置为 true,则它应该 return 18。很简单,不是吗?
但是我的尝试显然很丑陋,或者充其量是笨拙的,甚至没有编译;我得到:
错误 CS0029 无法将类型 'int' 隐式转换为 'bool'
...和:
错误 CS1662 无法将 lambda 表达式转换为预期的委托类型,因为块中的某些 return 类型无法隐式转换为委托 return 类型
我不知道为什么它认为我正在尝试转换为 bool,我绝对不会理解第二个错误。
如果我将代码更改为:
return counselPoints.FirstOrDefault(i => i.CounselNum > LastCounselPoint).Where(j => j.BR).Select(k => k.CounselNum );
我得到:
错误 CS1061 'CounselPoints' 不包含 'Where' 的定义并且没有扩展方法 'Where' 接受类型 'CounselPoints' 的第一个参数可以是找到(您是否缺少 using 指令或程序集引用?)
...这也只会导致我告诉编译器,“除了九点,其他都倒下了;把它们放在另一条胡同上。”
解开这个难题的关键是什么?
使用查询时,首先需要使用过滤条件,然后才调用FirstOrDefault
:
return counselPoints
.Where(j => j.BR)
.Where(k => k.CounselNum > LastCounselPoint)
.Select(i => i.CounselNum)
.FirstOrDefault();
有 2 种类型的 LINQ 查询运算符 - immediate and deferred。 Where
是延迟运算符的例子,FirstOrDefault
是立即运算符。
在您的代码中,您在无序列表上使用了 FirstOrDefault
,因此您立即过滤了初始列表。
在我提供的示例代码中,我首先使用延迟运算符定义过滤器,然后才使用即时函数检索结果。
试试这个....
counselPoints
.Where(j => j.BR && j.CounselNum > LastCounselPoint)
.FirstOrDefault();
我认为 dotnetom 和 Chris Moutray 已经回答了这个问题,我只想做一个小的旁注:
下次您遇到 LINQ 语句问题时,请尝试将它们拆分为单独的语句。这样做你会发现 FirstOrDefault()
在 Where() 之前没有任何意义,因为它会 return 一个单一的对象,你不能在单一对象上使用 where,对吗? :)
我在你的例子(以及其他答案)中看到你写的 first-default 是这样的:.FirstOrDefault(i => i.CounselNum)
但我认为你不需要这个。
将第一个默认值视为过滤器而不是 select。
所以你需要这样写
return counselPoints
.Where(cp => cp.BR && cp.CounselNum > LastCounselPoint) // where clause
.Select(cp => cp.CounselNum) // select part
.FirstOrDefault(); // get top 1 only
*更新 > 存在
正如@Jannik 指出的那样,当没有匹配项时,returns 为零而不是 null。
如果同时测试存在性很重要,那么你可以这样写。
CounselPoint cp = counselPoints
.Where(cp => cp.BR && cp.CounselNum > LastCounselPoint) // where clause
.FirstOrDefault(); // get top 1 object of type CounselPoint
if (cp == null)
return null;
return cp.CounselNum;
请注意,您的方法的 return 类型必须是可为 null 的 int。请参阅下面添加的 ?
。
public static int? GetNextBibleReadingCounselPoint(int LastCounselPoint)
...然后我猜你调用代码来检查结果
int? result = GetNextBibleReadingCounselPoint(lastCounselPoint);
if (result.HasValue) {
// something was returned
} else {
// nothing was returned
int num = result.Value;
}
*update2 > 订单
想着你的原创SQL - 不知道你是不是考虑下订单了??
也许你应该在底部添加一个订单:
SELECT TOP 1 CounselNumber
FROM COUNSELPOINTSLU
WHERE BR IS TRUE
AND CounselNumber > @LastCounselPoint
ORDER BY CounselNumber; // ascending
在这种情况下,您可以在 linq 语句中的 where 子句之前添加 order-by;像这样
return counselPoints
.OrderBy(cp => cp.CounselNum) // order by ascending
.Where( ... rest of code