使用java中的lambdas和stream将列表与公共列合并

时间:2017-01-06 09:05:04

标签: java lambda java-8 java-stream

我有两个场景,下面有两个域对象:

List<String> 1 = { id1,id2 ,id3}
List<String> 2 = { "one","two","three"}

1)我有4个列表

List<String> 3 =  { "one","two","three"}
List<String> 4 =  { 1,2,3}

注意 - 列表1元素对应于列表2元素,如id1 =&#34;一个&#34; ,id2 =&#34;两个&#34;等等

List<A> onjList = {[id=id1,name=one,value=1] , [id=id2,name=two,value=2] ,[id=id3,name=three,value=3]..... } 

注 - 列表3元素对应于列表4元素,如&#34;一个&#34; = 1,&#34;两个&#34; = 2等等

这些列表的所有值都对应于A类的属性,所以更多的列表与上面的所有属性一样,因此可能无法制作上述两个列表的地图。

我想要的是根据公共字段合并这些列表,即名称(值为列表2和列表3),如

List<A> onjList - {[id=id1,name=one,value=1] , [id=id2,name=two,value=2] ,[id=id3,name=three,value=3]..... } -----obtained from Step 1
List<PropVal> list 2 = { [id=id1,propVal1=w,propVal2=x,propVal3=y,propVal4=z] , [id=id2,propVal1=a,propVal2=b,propVal3=c,propVal4=d] ....}

2)我有两个列表

List<A> final List = {[id=id1,name=one,value=1,val1=w ,val2=x] , [id=id2,name= two,value = 2,val1 = a ,val2 = b]..... }

我想要一个像

这样的最终清单
public class TimerTest extends GdxTest {
    @Override
    public void create () {
        Timer timer = new Timer();
        Task task = timer.scheduleTask(new Task() {
            @Override
            public void run () {
                Gdx.app.log("TimerTest", "ping");
            }
        }, 1, 1);

        Gdx.app.log("TimerTest","is task scheduled: "+String.valueOf(task.isScheduled()));
    }
}

注意val1 = propVal1和val2 = propVal2。

这两种情况的最佳方法是什么?最好使用java 8流和lambdas?

2 个答案:

答案 0 :(得分:2)

您的示例具有误导性。数字没有很好的变量名称,所有四个列表都是相同的顺序,但我认为,你的问题应该暗示前两个列表的顺序可能与其他两个不同,例如。

List<String> aNames=Arrays.asList("one", "two", "three");
List<String> aIDs  =Arrays.asList("id1", "id2", "id3");

List<String> bNames =Arrays.asList("two", "one", "three");
List<String> bValues=Arrays.asList("2",   "1",   "3");

虽然可以在一个步骤中合并所有列表,但重复的线性搜索会产生整体的二次时间复杂度,因此不鼓励这样做。相反,将两个相关列表合并到一个地图中,允许有效查找,然后将另外两个与地图合并:

assert bNames.size()==bValues.size();
Map<String,String> bNameToValue = IntStream.range(0, bNames.size())
    .collect(HashMap::new, (m,i) -> m.put(bNames.get(i),bValues.get(i)), Map::putAll);

assert aNames.size()==aIDs.size();
List<A> list = IntStream.range(0, aNames.size())
    .mapToObj(i -> new A(aIDs.get(i), aNames.get(i), bNameToValue.get(aNames.get(i))))
    .collect(Collectors.toList());

第二项任务的考虑因素是相似的。如果PropVal元素的列表顺序不同,即需要查找,则建议使用映射,这意味着让上一步生成映射可能更简单。

assert bNames.size()==bValues.size();
Map<String,String> bNameToValue = IntStream.range(0, bNames.size())
    .collect(HashMap::new, (m,i)->m.put(bNames.get(i),bValues.get(i)), Map::putAll);

assert aNames.size()==aIDs.size();
Map<String,A> idToA = IntStream.range(0, aNames.size())
    .mapToObj(i -> new A(aIDs.get(i), aNames.get(i), bNameToValue.get(aNames.get(i))))
    .collect(Collectors.toMap(A::getId, Function.identity()));

List<PropVal> list2 = …

然后,如果A是可变的:

list2.forEach(pVal -> {
    A a = idToA.get(pVal.id);
    a.setVal1(pVal.propVal1);
    a.setVal2(pVal.propVal2);
    a.setVal3(pVal.propVal3);
    a.setVal4(pVal.propVal4);
});

List<A> finalList = new ArrayList<>(idToA.values());

A是不可变的:

List<A> finalList = list2.stream()
     .map(pVal -> {
        A a = idToA.get(pVal.id);
        return new A(pVal.id, a.getName(), a.getValue(),
            pVal.propVal1, pVal.propVal2, pVal.propVal3, pVal.propVal4);
        })
     .collect(Collectors.toList());

(请注意,这仅包含列表中的A个实例,其中存在PropVal

答案 1 :(得分:0)

请不要滥用java 8功能!您有数据设计缺点。在类中提供有用的方法,迁移到合适的数据结构。在您的模型中,很容易得到不一致的数据。

不要将所有问题委托给lambdas和溪流。