我有以下代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace OrderByElementSubelement
{
class Program
{
static void Main(string[] args)
{
List<Place> places = new List<Place>();
places.Add(new Place { Address = "Fifth Street", Score = 29, Houses = new List<House> { new House { Owner = "Mike", Score = 32 }, new House { Owner = "Bobby", Score = 3 } } });
places.Add(new Place { Address = "Sixth Street", Score = 29, Houses = new List<House> { new House { Owner = "Mike", Score = 42 }, new House { Owner = "Ted", Score = 45 } } });
places.Add(new Place { Address = "Seventh Street", Score = 29, Houses = new List<House> { new House { Owner = "Randy", Score = 84 }, new House { Owner = "William", Score = 1 } } });
var placesWithMikesHouseOrderedByMikesHouseScore = places.Where(x => x.Houses.Where(y => y.Owner == "Mike").Count() > 0).OrderBy(x => x.Houses.Where(y => y.Owner == "Mike").Select(z => z.Score)).ToList();
}
public class Place
{
public string Address { get; set; }
public int Score { get; set; }
public List<House> Houses { get; set; }
}
public class House
{
public string Owner { get; set; }
public int Score { get; set; }
}
}
}
它引发了这个异常:
An unhandled exception of type 'System.ArgumentException' occurred in mscorlib.dll
Additional information: At least one object must implement IComparable.
我正在尝试查询迈克的房子在那个地方以迈克的房子的分数排序的地方(你可以从上面看到这个想法)。一个地方有一个房子列表。 重要提示:您可以假设没有个别所有者可以在每个地方拥有多个房屋!
为什么它希望对象在这里实现IComparable,以及如何使这个查询有效?
答案 0 :(得分:8)
您的OrderBy
函数返回一个集合,而不是单个元素:
OrderBy(x => x.Houses.Where(y => y.Owner == "Mike").Select(z => z.Score))
您需要将其约束为分数,而不是IEnumerable<double>
(如果Score
是double
),即:
OrderBy(x => x.Houses.First(y => y.Owner == "Mike").Score)
请注意,如果没有"Mike"
作为所有者的房子,则会抛出此内容,但是,您的第一个过滤器应该处理该内容。
答案 1 :(得分:3)
在这里,我只删除了你的OrderBy
条款:
OrderBy(x => x.Houses.Where(y => y.Owner == "Mike").Select(z => z.Score))
您的问题是即使x.Houses.Where().Select()
只有一个元素,它仍然会返回IEnumerable
,但不会实现IComparable
并且无法进行排序。
您只想选择该集合中的第一项,以便您有几个选项:
OrderBy(x => x.Houses.Where(y => y.Owner == "Mike").Select(z => z.Score).Single())
OrderBy(x => x.Houses.Where(y => y.Owner == "Mike").Select(z => z.Score).SingleOrDefault())
OrderBy(x => x.Houses.Where(y => y.Owner == "Mike").Select(z => z.Score).First())
OrderBy(x => x.Houses.Where(y => y.Owner == "Mike").Select(z => z.Score).FirstOrDefault())
每个行为都有不同的行为如果集合包含多个元素,相同行为,如果它只包含一个元素。
答案 2 :(得分:1)
与里德的答案类似
var foo = places.Where(p => p.Houses.Any(h => h.Owner == "Mike"))
.OrderBy(p => p.Houses.Single(h => h.Owner == "Mike").Score);
(切线:你的第一个 Where()。Count&gt; 0 应该只是 Any())
正如其他答案所指出的那样,OrderBy只需要提供分数。或者,您可以make your House class implement IComparable允许您直接对房屋进行排序。
如果您要求Mike只在一个地方拥有一栋房屋,那么您可能希望在一个地方获得所有Mike房屋的最佳分数,在这种情况下,您可以调整为以下内容......
.OrderBy(p => p.Houses.Where(h => h.Owner == "Mike").Max(h => h.Score));
(关于OrderBy与OrderByDescending和Max vs Min的逻辑没有真正考虑过)