Reputation: 422
public class Witness
{
public Mobile m_mobile;
public bool m_hasLOS;
public double m_distanceToSqrt;
public Witness(Mobile m, bool hasLOS, double distanceToSqrt)
{
m_mobile = m;
m_hasLOS = hasLOS;
m_distanceToSqrt = distanceToSqrt;
}
}
I've created a list of these objects 'witnesses' and now want to sort it on both m_hasLOS and m_distanceToSqrt.
In my code I call:
List<Witness> sorted = witnesses.OrderBy(x => x.m_hasLOS).ThenBy(x => x.m_distanceToSqrt).ToList();
This works, but the list is not ordered how I would like. How do I change the ordering such that: LOS is always at the top of the list, ordered on ascending distance? And where LOS is false, the list is then just ascending distance?
For example:
o1: m_LOS = true, m_distanceToSqrt = 13
o2: m_LOS = false, m_distanceToSqrt = 6
o3: m_LOS = false, m_distanceToSqrt = 2
Should yield the reaultant sort:
o1: m_LOS = true, m_distanceToSqrt = 13
o3: m_LOS = false, m_distanceToSqrt = 2
o2: m_LOS = false, m_distanceToSqrt = 6
Upvotes: 1
Views: 692
Reputation: 7179
In the C family of languages (and many others), you can think of false
as being equal to 0
and true
being equal to 1
(more specifically anything that is not 0
).
So sorting on a boolean
field will return all false
values first when the sort order is ascending because 0 < 1
. If you want the true
values first, you will need to use the descending sort order.
For OrderBy
, that is OrderByDescending
. For ThenBy
, that is ThenByDescending
. In your case, you just need to use the first.
List<Witness> sorted = witnesses
.OrderByDescending(x => x.m_hasLOS)
.ThenBy(x => x.m_distanceToSqrt)
.ToList();
Side note, public members should use pascal casing, properties should be preferred over public fields in order to abstract implementation details from class responsibilities, and variable names should favor readability over length.
The conventional way to write your class definition would be:
public class Witness
{
private Mobile mobile;
private bool hasLineOfSight;
private double distanceToSquareRoot;
public Mobile Mobile
{
get => mobile;
set => mobile = value;
}
public bool HasLineOfSight
{
get => hasLineOfSight;
set => hasLineOfSight = value;
}
public double DistanceToSquareRoot
{
get => distanceToSquareRoot;
set => distanceToSquareRoot = value;
}
public Witness(Mobile mobile, bool hasLineOfSight, double distanceToSquareRoot)
{
Mobile = mobile;
HasLineOfSight = hasLineOfSight;
DistanceToSquareRoot = distanceToSquareRoot;
}
}
Since you don't have any methods on your class, if its primary use is as a value type, you could use the record
type instead.
public record Witness(
Mobile Mobile,
bool HasLineOfSight,
double DistanceToSquareRoot
);
Upvotes: 3