简体   繁体   中英

How to sort a list using reduce in java 8?

I have list of objects List<BoM> in BoM I have a List<BoMLine> , now I have to sort BoM list by one of BoMLine property using reduce and return a sorted List in a method,

public static List<BoM> sortBoms() {
    List<BoM> sortedBomList = new ArrayList<>();
    BoM bomn = new BoM();
    sortedBomList.add(bomList.parallelStream().reduce(bomn,
            (bom1, bom2) -> sortBoM(bom1, bom2)));
    System.out.println(sortedBomList.size());
    return sortedBomList;
}

bomList is List of BoM,and sortBoM method:

private static BoM sortBoM(BoM bom1, BoM bom2) {
    bom2.getLine().stream()
            .sorted((l1, l2) -> l1.getLineNum().compareTo(l2.getLineNum()));
    bom1 = bom2;
    return bom1;
}

BoM class:

public class BoM implements Domain {

private String BomCode;
private List<BoMLine> line = new ArrayList<BoMLine>();

public String getBomCode() {
    return BomCode;
}

public void setBomCode(String bomCode) {
    BomCode = bomCode;
}

public List<BoMLine> getLine() {
    return line;
}

public void setLine(List<BoMLine> line) {
    this.line = line;
}

public void addLine(BoMLine bomLine) {
    bomLine.setbOM(this);
    line.add(bomLine);
}}

and BoMLine class:

public class BoMLine implements Domain {

private Long lineNum;
private String material;
private BigDecimal Qty;
private BoM bOM;

public Long getLineNum() {
    return lineNum;
}

public void setLineNum(Long lineNum) {
    this.lineNum = lineNum;
}

public String getMaterial() {
    return material;
}

public void setMaterial(String material) {
    this.material = material;
}

public BigDecimal getQty() {
    return Qty;
}

public void setQty(BigDecimal qty) {
    Qty = qty;
}

public BoM getbOM() {
    return bOM;
}

public void setbOM(BoM bOM) {
    this.bOM = bOM;
}

public String getBoMCode() {
    return bOM.getBomCode();
}

@Override
public String toString() {
    return "BoMLine [ bOM=" + bOM.getBomCode() + ", lineNum=" + lineNum
            + ", material=" + material + ", Qty=" + Qty + "]";
}}

I have to order BoM list by BoMLine lineNum. but it just returns one object of bomList.Any help?

You can sort each BoMLine in ascending order of the line number by creating a custom Comparator using Comparator.comparing :

List<BoM> sortedBomList = new ArrayList<>();
sortedBomList.forEach(bom -> bom.getLine().sort(comparing(BoMLine::getLineNum)));

Note that this will mutate the List<BoMLine> and List<BoM> which might not be a good idea.

A better way would be to go for immutability and create a constructor taking the bom code and bom line list:

List<BoM> sortedBomList = 
        bomList.stream()
               .map(bom -> new BoM(
                               bom.BomCode,
                               bom.getLine().stream()
                                            .sorted(comparing(BoMLine::getLineNum))
                                            .collect(toList())
                           )
               )
               .collect(toList());

You would not be able to get a sorted list with reduce. For getting a sorted list back you would have to use sorted in sortBoms() method followed by a collect logic that returns a list.

The modified code would look like the snippet below:

sortedBomList.add(bomList.parallelStream().sorted(byBoMLineProperty).collect(Collectors.toList());

This would also entail implementing byBoMLineProperty comparator that compares two BoM by its BoMLine property.

You have drastically overcomplicated your question by posting a lot of irrelevant code. What you are asking about is how to sort a list of numbers using reduce , so the entire problem can be effectively simplified to implementing method List<Integer> sorted(List<Integer> list) .

Please note that although this is possible, it is inefficient and solution shown by Tunaki is recommended. I guess this is part of some university assignment.

import org.junit.Test;

import java.util.ArrayList;
import java.util.List;
import java.util.PriorityQueue;

import static java.util.Arrays.asList;
import static java.util.Collections.singleton;
import static junit.framework.Assert.assertEquals;

public class ReductionSortingTest {

    @Test
    public void sortsTheList() {
        List<Integer> list =     asList(5,  3, 9, 8, 15, -4, 9);
        List<Integer> expected = asList(-4, 3, 5, 8, 9,  9,  15);

        List<Integer> sorted = sorted(list);

        assertEquals(expected, sorted);
    }

    private static List<Integer> sorted(List<Integer> list) {
        PriorityQueue<Integer> pq = list.stream()
                .map((Integer n) -> new PriorityQueue<>(singleton(n)))
                .reduce(new PriorityQueue<>(), (pq1, pq2) -> {
                    pq1.addAll(pq2);
                    return pq1;
                });

        List<Integer> result = new ArrayList<>();
        while (!pq.isEmpty()) {
            result.add(pq.poll());
        }
        return result;
    }

}

Java lacks a sorted list so I decided to go with PriorityQueue , read more about it in this question . PriorityQueue guarantees that the top element (accessed via peek() , poll() methods) is the lowest according to the natural ordering of elements. Order of elements returned by its iterator is not guaranteed, hence why we have to empty the queue using poll() method - you might want to implement your own SortedList class instead.

EDIT:

Here is a sorted list solution. Keep in mind that although there is no final iteration and it uses binary search, its efficiency is far from simple sort (we are talking probably about O(n^3) ).

private List<Integer> sorted(List<Integer> list) {
    return list.stream()
            .map(SortedIntList::new)
            .reduce(new SortedIntList(), (a, b) -> {
                a.addAll(b);
                return a;
            });
}

private static class SortedIntList extends ArrayList<Integer> {

    public SortedIntList() {}

    public SortedIntList(int element) {
        super(singletonList(element));
    }

    @Override
    public boolean add(Integer integer) {
        int insertionPoint = Collections.binarySearch(this, integer);
        if (insertionPoint < 0) {
            insertionPoint = -insertionPoint - 1;
        }
        super.add(insertionPoint, integer);
        return true;
    }

    @Override
    public boolean addAll(Collection<? extends Integer> c) {
        c.forEach(this::add);
        return true;
    }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM