2015-11-03 112 views
3

我在物料清单的对象List<BoM>的名单我有一个List<BoMLine>,现在我已经通过减少在一个方法返回一个排序列表BoMLine属性的一个排序BoM列表,如何使用java 8中的reduce对列表进行排序?

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 2是BOM清单和sortBoM方法:

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

物料清单类:

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); 
}} 

和BoML ine类:

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 + "]"; 
}} 

我必须通过BoMLine lineNum订购BoM列表。 但它只是返回bomList.Any帮助的一个对象?

+0

你能发表一个输入和想要的输出的例子吗?我不确定我了解每个“BoM”应该如何排序。 – Tunaki

+0

编辑帖子,请看看 – Nazila

+0

我还是不明白'BoM'对象应该如何排序。您可以通过行号对'List '进行排序,但这无助于将两个“BoM”进行比较。 – Tunaki

回答

2

您可以通过创建使用Comparator.comparing定制Comparator行号的升序每个BoMLine排序:

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

注意,这会产生变异的List<BoMLine>List<BoM>这可能不是一个好主意。

一个更好的方式是去不变性和创建一个构造函数取BOM编码和BOM表行:

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

不,我必须使用减少 – Nazila

+1

@nazila你什么意思,你“必须使​​用减少”做些什么的问题?您无法使用reduce对列表进行排序,这不是该方法的用途。你真的想在这里做什么? – Tunaki

+0

你可以实现所有这些方法的减少,但我不知道如何 – Nazila

0

您将无法获得与减少排序列表。为了得到一个排序列表,你必须使用sortBoms()方法中的排序,然后是一个返回列表的收集逻辑。

修改后的代码看起来像下面的片段:

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

这也将需要执行byBoMLineProperty比较器通过其BoMLine属性两个物料清单进行比较。

+0

我必须使用reduce。 – Nazila

-2

通过发布大量不相关的代码,您已经大大地过分复杂化了您的问题。你所问的是如何使用reduce对数字列表进行排序,因此整个问题可以有效地简化为实现方法List<Integer> sorted(List<Integer> list)

请注意,虽然这是可能的,但效率低下,推荐使用Tunaki显示的解决方案。我想这是大学任务的一部分。

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缺乏一个排序列表,所以我决定去与PriorityQueue,阅读更多关于它在this question。根据元素的自然顺序,PriorityQueue保证顶层元素(通过peek(),poll()方法访问)最低。无法保证其迭代器返回的元素顺序,因此为什么我们必须使用poll()方法清空队列 - 您可能需要实现自己的SortedList类。

编辑:

这里是一个排序列表的解决方案。请记住,虽然没有最终的迭代,并且它使用二分搜索,但其效率远非简单排序(我们正在谈论的可能大约是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; 
    } 

} 
+2

您正在使用'reduce'不排序,你只是添加元素的内在有序集合,这是,顺便说一句,一个无效的使用reduce'的',因为它的变异的输入值。 – Holger

+0

@Holger 1.据我了解的问题,任务是使用'流()排序减少(...)',而不是'流()排序()' - 。我们都知道它不这很有意义,Tunaki详细解释了它。 2.我使用'reduce'的方式绝对有效。我决定改变输入值,而不是每次都创建新的集合,因为它们的效率很高,但是所有这些优先级队列仅在本方法内部使用。 –

+3

也许你想读作[文件](http://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html#Reduction)第一和理解之间的“差异减少“和”可变减少“。对于后者,有一种专用的方法,使用“collect”来代替滥用“reduce”。你不是决定使用是否“绝对有效”的人,这取决于API设计者决定什么是正确的用法,他们已经做到了。 – Holger