การเปลี่ยนคอลเลกชันของตัวเลข (หรือออบเจ็กต์ที่เป็นฟิลด์ที่คุณต้องการตรวจสอบ) เป็นการแจกแจงตัวเลขเหล่านี้เป็นเทคนิคทางสถิติทั่วไป และใช้ในบริบทต่างๆ ในการรายงานและแอปพลิเคชันที่อิงตามข้อมูล
ให้คอลเลกชัน:
1, 1, 2, 1, 2, 3, 1, 4, 5, 1, 3
คุณสามารถตรวจสอบการแจกแจงเป็นจำนวน (ความถี่ของแต่ละองค์ประกอบ) และเก็บผลลัพธ์ไว้ในแผนที่:
{
"1": 5,
"2": 2,
"3": 2,
"4": 1,
"5": 1
}
หรือคุณสามารถ ทำให้ปกติ ค่าตามจำนวนค่าทั้งหมด – ซึ่งแสดงเป็นเปอร์เซ็นต์:
{
"1": 0.45,
"2": 0.18,
"3": 0.18,
"4": 0.09,
"5": 0.09
}
หรือแม้แต่แสดงเปอร์เซ็นต์เหล่านี้ใน a 0..100
รูปแบบแทนa 0..1
จัดรูปแบบ
ในคู่มือนี้ เราจะมาดูกันว่าคุณสามารถคำนวณการกระจายจากคอลเลกชันได้อย่างไร ทั้งการใช้ประเภทดั้งเดิมและวัตถุที่เป็นฟิลด์ที่คุณอาจต้องการรายงานในแอปพลิเคชันของคุณ
ด้วยการเพิ่มการรองรับการทำงานโปรแกรมใน Java การคำนวณการแจกแจงจะง่ายกว่าที่เคย เราจะทำงานกับคอลเลกชันของตัวเลขและคอลเลกชันของ Book
s:
public class Book {
private String id;
private String name;
private String author;
private long pageNumber;
private long publishedYear;
}
คำนวณการกระจายของคอลเลกชันใน Java
อันดับแรก มาดูวิธีคำนวณการแจกแจงสำหรับประเภทดั้งเดิมกันก่อน การทำงานกับอ็อบเจ็กต์ทำให้คุณสามารถเรียกใช้เมธอดแบบกำหนดเองจากคลาสโดเมนของคุณ เพื่อให้การคำนวณมีความยืดหยุ่นมากขึ้น
โดยค่าเริ่มต้น เราจะแสดงเปอร์เซ็นต์เป็นสองเท่าจาก 0.00
ไปยัง 100.00
.
ประเภทดั้งเดิม
มาสร้างรายการจำนวนเต็มและพิมพ์การแจกแจงกัน:
List integerList = List.of(1, 1, 2, 1, 2, 3, 1, 4, 5, 1, 3);
System.out.println(calculateIntegerDistribution(integerList));
การกระจายคำนวณด้วย:
public static Map calculateIntegerDistribution(List list) {
return list.stream()
.collect(Collectors.groupingBy(Integer::intValue,
Collectors.collectingAndThen(Collectors.counting(),
count -> (Double.parseDouble(String.format("%.2f", count * 100.00 / list.size()))))));
}
วิธีนี้ยอมรับรายการและสตรีม ขณะสตรีม ค่าคือ จัดกลุ่มโดย ค่าจำนวนเต็ม – และค่าของมันคือ นับ การใช้ Collectors.counting()
ก่อนรวบรวมเป็น Map
โดยที่คีย์แสดงค่าอินพุตและคู่แสดงแทนเปอร์เซ็นต์ในการแจกแจง
วิธีการหลักที่นี่คือ collect()
ซึ่งยอมรับ นักสะสมสองคน. key-collector รวบรวมโดยเพียงแค่จัดกลุ่มตามค่าคีย์ (องค์ประกอบอินพุต) นักสะสมมูลค่ารวบรวมผ่าน collectingAndThen()
ซึ่งช่วยให้เราสามารถ นับค่า แล้วจัดรูปแบบในรูปแบบอื่น เช่น count * 100.00 / list.size()
ซึ่งช่วยให้เราแสดงองค์ประกอบที่นับเป็นเปอร์เซ็นต์:
{1=45.45, 2=18.18, 3=18.18, 4=9.09, 5=9.09}
จัดเรียงการกระจายตามค่าหรือคีย์
เมื่อสร้างการแจกแจง คุณมักจะต้องการเรียงลำดับค่า บ่อยกว่านี้จะเป็นโดย สำคัญ. ชวา HashMap
s ไม่รับประกันว่าจะรักษาลำดับการแทรกดังนั้นเราจะต้องใช้ a LinkedHashMap
ซึ่งไม่ นอกจากนี้ วิธีที่ง่ายที่สุดในการสตรีมแผนที่ซ้ำและรวบรวมใหม่ในขณะนี้ เนื่องจากมีขนาดเล็กกว่ามากและสามารถจัดการได้มากขึ้น
การดำเนินการก่อนหน้านี้สามารถยุบระเบียนหลายพันรายการลงในแผนที่ขนาดเล็กได้อย่างรวดเร็ว ทั้งนี้ขึ้นอยู่กับจำนวนคีย์ที่คุณกำลังติดต่อด้วย ดังนั้นการสตรีมซ้ำจึงไม่แพง:
public static Map calculateIntegerDistribution(List list) {
return list.stream()
.collect(Collectors.groupingBy(Integer::intValue,
Collectors.collectingAndThen(Collectors.counting(),
count -> (Double.parseDouble(String.format("%.2f", count.doubleValue() / list.size()))))))
.entrySet()
.stream()
.sorted(Map.Entry.comparingByKey())
.collect(Collectors.toMap(e -> Integer.parseInt(e.getKey().toString()),
Map.Entry::getValue,
(a, b) -> {
throw new AssertionError();
},
LinkedHashMap::new));
}
วัตถุ
สิ่งนี้สามารถทำได้สำหรับวัตถุ? ใช้ตรรกะเดียวกัน! แทนที่จะเป็นฟังก์ชันระบุ (Integer::intValue
) เราจะใช้ฟิลด์ที่ต้องการแทน เช่น ปีที่จัดพิมพ์สำหรับหนังสือของเรา มาสร้างหนังสือสองสามเล่ม เก็บไว้ในรายการ แล้วคำนวณการแจกแจงปีที่พิมพ์:
ดูคู่มือเชิงปฏิบัติสำหรับการเรียนรู้ Git ที่มีแนวทางปฏิบัติที่ดีที่สุด มาตรฐานที่ยอมรับในอุตสาหกรรม และเอกสารสรุปรวม หยุดคำสั่ง Googling Git และจริงๆ แล้ว เรียน มัน!
Book book1 = new Book("001", "Our Mathematical Universe", "Max Tegmark", 432, 2014);
Book book2 = new Book("002", "Life 3.0", "Max Tegmark", 280, 2017);
Book book3 = new Book("003", "Sapiens", "Yuval Noah Harari", 443, 2011);
Book book4 = new Book("004", "Steve Jobs", "Water Isaacson", 656, 2011);
List books = Arrays.asList(book1, book2, book3, book4);
ลองคำนวณการกระจายของ publishedYear
สนาม:
public static Map calculateDistribution(List books) {
return books.stream()
.collect(Collectors.groupingBy(Book::getPublishedYear,
Collectors.collectingAndThen(Collectors.counting(),
count -> (Double.parseDouble(String.format("%.2f", count * 100.00 / books.size()))))))
.entrySet()
.stream()
.sorted(Map.Entry.comparingByKey())
.collect(Collectors.toMap(e -> Integer.parseInt(e.getKey().toString()),
Map.Entry::getValue,
(a, b) -> {
throw new AssertionError();
},
LinkedHashMap::new));
}
ปรับตัว "%.2f"
เพื่อกำหนดความแม่นยำของจุดลอยตัว ส่งผลให้:
{2011=50.0, 2014=25.0, 2017=25.0}
50% ของหนังสือที่กำหนด (2/4) ตีพิมพ์ในปี 2011, 25% (1/4) ตีพิมพ์ในปี 2014 และ 25% (1/4) ในปี 2017 จะเป็นอย่างไรถ้าคุณต้องการจัดรูปแบบผลลัพธ์นี้ให้แตกต่างออกไปและทำให้เป็นมาตรฐาน ช่วงใน 0..1
?
คำนวณการกระจายแบบปกติ (เปอร์เซ็นต์) ของคอลเล็กชันใน Java
เพื่อทำให้เปอร์เซ็นต์ปกติจาก a 0.0...100.0
ช่วงถึง a 0..1
ช่วง – เราเพียงแค่ปรับ collectingAndThen()
เรียกร้องให้ ไม่ คูณการนับด้วย 100.0
ก่อนจะหารด้วยขนาดของสะสม
ก่อนหน้านี้ Long
นับส่งคืนโดย Collectors.counting()
ถูกแปลงเป็นทวีคูณโดยปริยาย (การคูณด้วยค่าสองเท่า) ดังนั้นคราวนี้ เราจึงต้องการได้ค่า doubleValue()
ของ count
:
public static Map calculateDistributionNormalized(List books) {
return books.stream()
.collect(Collectors.groupingBy(Book::getPublishedYear,
Collectors.collectingAndThen(Collectors.counting(),
count -> (Double.parseDouble(String.format("%.4f", count.doubleValue() / books.size()))))))
.entrySet()
.stream()
.sorted(comparing(e -> e.getKey()))
.collect(Collectors.toMap(e -> Integer.parseInt(e.getKey().toString()),
Map.Entry::getValue,
(a, b) -> {
throw new AssertionError();
},
LinkedHashMap::new));
}
ปรับตัว "%.4f"
เพื่อกำหนดความแม่นยำของจุดลอยตัว ส่งผลให้:
{2011=0.5, 2014=0.25, 2017=0.25}
คำนวณจำนวนองค์ประกอบ (ความถี่) ของคอลเลกชัน
สุดท้าย – เราสามารถรับการนับองค์ประกอบ (ความถี่ขององค์ประกอบทั้งหมด) ในคอลเล็กชัน โดยเพียงแค่ไม่หารการนับด้วยขนาดของคอลเล็กชัน! นี่คือการนับที่ไม่ได้ทำให้เป็นมาตรฐานโดยสมบูรณ์:
public static Map calculateDistributionCount(List books) {
return books
.stream()
.collect(Collectors.groupingBy(Book::getPublishedYear,
Collectors.collectingAndThen(Collectors.counting(),
count -> (Integer.parseInt(String.format("%s", count.intValue()))))))
.entrySet()
.stream()
.sorted(Map.Entry.comparingByKey())
.collect(Collectors.toMap(e -> Integer.parseInt(e.getKey().toString()),
Map.Entry::getValue,
(a, b) -> {
throw new AssertionError();
},
LinkedHashMap::new));
}
ผลลัพธ์นี้ใน:
{2011=2, 2014=1, 2017=1}
อันที่จริงมีหนังสือสองเล่มจากปี 2011 และหนึ่งเล่มจาก 2014 และ 2017 แต่ละเล่ม
สรุป
การคำนวณการกระจายข้อมูลเป็นงานทั่วไปในแอปพลิเคชันที่มีข้อมูลจำนวนมาก และไม่จำเป็นต้องใช้ไลบรารีภายนอกหรือโค้ดที่ซับซ้อน ด้วยการสนับสนุนการเขียนโปรแกรมที่ใช้งานได้ Java ทำให้การทำงานกับคอลเลกชันเป็นเรื่องง่าย!
ในฉบับร่างสั้นๆ นี้ เราได้พิจารณาถึงวิธีที่คุณสามารถคำนวณการนับความถี่ขององค์ประกอบทั้งหมดในคอลเลกชั่น ตลอดจนวิธีการคำนวณแผนที่การกระจายที่ปรับให้เป็นเปอร์เซ็นต์ระหว่าง 0
และ 1
และ 0
และ 100
ใน Java