Выполнять левые внешние соединения в linq C # // Выполнять левые внешние соединения
class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
class Child
{
public string Name { get; set; }
public Person Owner { get; set; }
}
public class JoinTest
{
public static void LeftOuterJoinExample()
{
Person magnus = new Person { FirstName = "Magnus", LastName = "Hedlund" };
Person terry = new Person { FirstName = "Terry", LastName = "Adams" };
Person charlotte = new Person { FirstName = "Charlotte", LastName = "Weiss" };
Person arlene = new Person { FirstName = "Arlene", LastName = "Huff" };
Child barley = new Child { Name = "Barley", Owner = terry };
Child boots = new Child { Name = "Boots", Owner = terry };
Child whiskers = new Child { Name = "Whiskers", Owner = charlotte };
Child bluemoon = new Child { Name = "Blue Moon", Owner = terry };
Child daisy = new Child { Name = "Daisy", Owner = magnus };
// Create two lists.
List people = new List { magnus, terry, charlotte, arlene };
List childs = new List { barley, boots, whiskers, bluemoon, daisy };
var query = from person in people
join child in childs
on person equals child.Owner into gj
from subpet in gj.DefaultIfEmpty()
select new
{
person.FirstName,
ChildName = subpet!=null? subpet.Name:"No Child"
};
// PetName = subpet?.Name ?? String.Empty };
foreach (var v in query)
{
Console.WriteLine($"{v.FirstName + ":",-25}{v.ChildName}");
}
}
// This code produces the following output:
//
// Magnus: Daisy
// Terry: Barley
// Terry: Boots
// Terry: Blue Moon
// Charlotte: Whiskers
// Arlene: No Child
Вот утилита, которая округляет (вместо усечения) двойку до заданного количества десятичных знаков.
Например:
round(200.3456, 2); // returns 200.35
public static double round(double value, int places) {
if (places < 0) throw new IllegalArgumentException();
long factor = (long) Math.pow(10, places);
value = value * factor;
long tmp = Math.round(value);
return (double) tmp / factor;
}
Эта сильно ломается в угловых случаях с очень большим количеством десятичных знаков (например, round(1000.0d, 17)
) или большой целой частью (например, round(90080070060.1d, 9)
). Спасибо Sloin за указание на это.
Я использовал вышеупомянутое для округления "не слишком больших" двоек до 2 или 3 знаков после запятой в течение многих лет (например, для очистки времени в секундах для целей протоколирования: 27.987654321987 -> 27.99). Но я полагаю, что лучше избегать этого, поскольку легко доступны более надежные способы, с более чистым кодом.
(Адаптировано из этого ответа Луиса Вассермана и этого ответа Шона Оуэна.)
public static double round(double value, int places) {
if (places < 0) throw new IllegalArgumentException();
BigDecimal bd = BigDecimal.valueOf(value);
bd = bd.setScale(places, RoundingMode.HALF_UP);
return bd.doubleValue();
}
Обратите внимание, что HALF_UP
- это способ округления, которому "обычно учат в школе". Просмотрите документацию RoundingMode, если вы подозреваете, что вам нужно что-то другое, например Bankers' Rounding.
Конечно, если вы предпочитаете, вы можете вставить вышеприведенное в одно предложение:
new BigDecimal(value).setScale(places, RoundingMode.HALF_UP).doubleValue()
Всегда помните, что представления с плавающей точкой с помощью float
и double
являются неточными.
Например, рассмотрим эти выражения:
999199.1231231235 == 999199.1231231236 // true
1.03 - 0.41 // 0.6200000000000001
Для точности вы хотите использовать BigDecimal. И при этом используйте конструктор, который принимает String, а не тот, который принимает double. Например, попробуйте выполнить следующее:
System.out.println(new BigDecimal(1.03).subtract(new BigDecimal(0.41)));
System.out.println(new BigDecimal("1.03").subtract(new BigDecimal("0.41")));
Несколько отличных дополнительных материалов по теме:
float
и double
, если требуются точные ответы" в Effective Java (2nd ed) by Joshua BlochЕсли вам нужно форматирование String вместо (или в дополнение к) строгому округлению чисел, смотрите другие ответы.
В частности, обратите внимание, что round(200, 0)
возвращает 200.0
. Если вы хотите вывести "200.00", вы должны сначала округлить, а затем отформатировать результат для вывода (что прекрасно объяснено в ответе Jesper'а).
Если вы просто хотите вывести double
с двумя цифрами после запятой, используйте что-то вроде этого:
double value = 200.3456;
System.out.printf("Value: %.2f", value);
Если вы хотите получить результат в String
вместо вывода в консоль, используйте String. format()
с теми же аргументами:
String result = String.format("%.2f", value);
Или используйте класс DecimalFormat
:
DecimalFormat df = new DecimalFormat("####0.00");
System.out.println("Value: " + df.format(value));
Самый простой способ - проделать такой трюк;
double val = ....;
val = val*100;
val = Math.round(val);
val = val /100;
если значение val начинается с 200,3456, оно переходит к 20034,56, а затем округляется до 20035 затем мы делим его, чтобы получить 200,34.
если вы хотите всегда округлять в меньшую сторону, мы всегда могли бы выполнить усечение, приведя к типу int:
double val = ....;
val = val*100;
val = (double)((int) val);
val = val /100;
Этот метод будет работать в большинстве случаев, потому что для очень больших удвоений (положительных или отрицательных) он может переполняться. но если вы знаете, что ваши значения будут в соответствующем диапазоне, тогда это должно сработать для вас.
Округление дубля обычно не то, что нужно. Вместо этого используйте String.format ()
, чтобы представить его в желаемом формате.
В вашем вопросе, похоже, вы также хотите избежать округления чисел? Я думаю, что .format () будет округлять числа, используя половину вверх, afaik?
, поэтому, если вы хотите округлить, 200,3456 должно быть 200,35 для точности 2, но в вашем случае, если вы просто хотите первые 2, а затем отбросить остальные?
Вы можете умножить его на 100, а затем преобразовать его в int (или взять нижний предел числа), прежде чем снова разделить на 100.
200.3456 * 100 = 20034.56;
(int) 20034.56 = 20034;
20034/100.0 = 200.34;
Однако у вас могут возникнуть проблемы с действительно большими числами вблизи границы. В этом случае преобразование в строку и подстроку будет работать так же легко.