我想从代码中显示的列表中找到最接近的相等或更大的纸张尺寸。
List<PaperSize> paper = new List<PaperSize>();
paper.Add(new PaperSize("B5", 516, 729));
paper.Add(new PaperSize("A5", 420, 595));
paper.Add(new PaperSize("A4", 595, 842));
paper.Add(new PaperSize("B4", 729, 1032));
paper.Add(new PaperSize("A4L", 842, 595));
paper.Add(new PaperSize("A3", 1191, 842));
paper.Add(new PaperSize("A2", 1685, 1190));
paper.Add(new PaperSize("A1", 2384, 1685));
paper.Add(new PaperSize("A0", 3371, 2384));
int width = 1189;
int height = 840;
string name = paper.SkipWhile(p => p.PaperWidth < width && p.PaperHeight <
height).First().PaperName;
Console.WriteLine("Nearest equal or larger papersize is " + name);
如果我提供宽度1189和高度840,我希望选择纸张A3,但结果是A4。 如何退回A3?
编辑:确实,列表并不总是以特定的方式排序。因此,@ Johnny和@Knoop的建议解决了我的问题。紧接着,我忘记将PaperSize及其属性PaperName,PaperWidth和PaperHeight包括在内,但是你们所有人都正确地认为我拥有此属性。
答案 0 :(得分:6)
将您的&&
更改为||
。您想在宽度或太小时跳过。
string name = paper.SkipWhile(p => p.PaperWidth < width || p.PaperHeight <
height).First().PaperName;
当然,另一种也许更清晰的书写方式是:
string name = paper
.First(p => p.PaperWidth >= width && p.PaperHeight >= height)
.PaperName;
还应该考虑以下事实:纸张尺寸可能不够大。在这种情况下,会将name
设置为null。
string name = paper
.FirstOrDefault(p => p.PaperWidth >= width && p.PaperHeight >= height)
?.PaperName;
当然,只有在您的纸张尺寸列表严格按区域排序(从最小到最小)的情况下,这些选项才起作用。如果不是这种情况,则可以选择浪费空间最小的纸张尺寸:
int area = width * height;
string name = paper
.Where(p => p.PaperWidth >= width && p.PaperHeight >= height)
.OrderBy(p => p.PaperWidth * p.PaperHeight - area)
.FirstOrDefault()
?.PaperName;
答案 1 :(得分:3)
尝试此操作,paper
列表不应预先排序:
paper.Where(p => p.PaperWidth - width >= 0 && p.PaperHeight - height >= 0)
.OrderBy(p => p.PaperWidth - width + p.PaperHeight - height)
.FirstOrDefault();
答案 2 :(得分:0)
要求:
给定宽度和高度后,请给我命名为小于此宽度和高度的最小PaperSize的名称
对此有些棘手。
假设宽度和高度分别为100和100。您有两张纸:
两张纸都足够大。如果您先看一下宽度,您会选择纸张A,因为它的宽度最小。但是,纸B似乎比纸A小得多。
因此,首先您必须自己思考:什么时候Paper比另一Paper小?。您将需要实现IComparer<PaperSize>
的PaperComparer类:
class PaperSizeComparer : Comparer<PaperSize>
{
public static IComparer AreaComparer {get;} = new PaperSizeComparer();
public override int Compare(PaperSize x, PaperSize y)
{
... TODO: implement your definition of smaller PaperSize
}
}
现在,您可以决定何时考虑一个PaperSize小于另一个PaperSize。您可以选择宽度,然后选择高度。就我个人而言,我会选择“面积”:
private static readonly IComparer<int> areaComparer = Comparer<int>.Default;
public int CalcArea(PaperSize x)
{
return x.Width * x.Height;
}
public override int Compare(PaperSize x, PaperSize y)
{
// null PaperSizes are smallest
if (x == null)
{
if (y == null)
// both null: equal
return 0;
else
// x null, y not null: x is smaller
return -1;
}
else if (y == null) return +1; // x not null; y null: larger
else
{ // x and y both not null: compare areas:
int areaX = this.CalcArea(x);
int areaY = this.CalcArea(y);
return areaComparer.Compare(areaX, areaY);
}
}
现在,您已经定义了比较器,您的LINQ很简单:
IEnumerable<PaperSize> availablePaperSizes = ...
int width = ...
int height = ...
请给我最小宽度大于高度和宽度的最小纸张的名称
var smallestFittingPapersizeName = availablePaperSizes
.Where(paperSize => paperSize.Width >= width && paperSize.Height >= height)
.OrderBy(paperSize, PaperSizeComparer.AreaComparer)
.Select(paperSize => paperSize.Name)
.FirstOrDefault();
在连接LINQ语句时,请始终确保只有最后一个语句是不返回IEnumerable的语句!
注意:
如果只需要最小尺寸的纸张,则订购所有纸张尺寸是非常浪费的。考虑使用Enumerable.Aggregate获得最小的PaperSize
// instead of OrderBy:
.Aggregate( (paperSizeX, paperSizeY) =>
((PaperSizeComparer.AreaComparer.Compare(paperSizeX, paperSizeY) <= 0) ??
// paperSizeX smaller or equal; X remains the smallest
paperSizeX :
// paperSizeX larger: Y is the new smalles:
paperSizeY)
A,这不适用于空集合。除此之外,它看起来还很朦胧。
考虑编写扩展函数,该函数在任何序列上返回最小或默认值:
public TSource MinOrDefault<TSource> (this IEnumerable<TSource> source,
IComparer<TSource) comparer)
{
// TODO: exception if source == null
if (comparer == null)
comparer = Comparer<TSource>.Default; // use default comparer
var enumerator = source.GetEnumerator();
if (enumerator.MoveNext())
{ // we have at least one source element:
var smallest = enumerator.Current;
// continue with the rest of the input sequence:
while (enumerator.MoveNext())
{
// there is still another item
if (comparer.CompareTo(smallest, enumerator.Current) > 0)
{
// found a smaller item:
smallest = enumerator.Current;
}
}
return smallest;
}
else
{ // input collection empty; return default
return default(TSource);
}
}
用法:
PaperSize smallestFittingPaperSize = availablePaperSizes
.Where(paperSize => paperSize.Width >= width && paperSize.Height >= height)
.Min(PaperSizeComparer.AreaCompaerer);