簡體   English   中英

如何使用Lambda-Expressions通過Key對KeyValue對象進行過濾?

[英]How to perform filtering by Key on KeyValue objects using Lambda-Expressions?

鑒於我想過濾鍵值對象列表。

我的(文檔) - 下面的示例中的對象看起來像這樣

{
    "attributeEntityList" : [
        {key: 'key1', value: 'somevalue1'},
        {key: 'key2', value: 'somevalue2'},
        {key: 'key3', value: 'somevalue3'}
    ]
}
  1. 當我傳入以下鍵["key1", "key2", "key3"] ,我希望我的函數返回整個給定的屬性列表。

  2. 當我傳入以下鍵["key1", "key2"]的列表時,我希望我的函數返回一個具有給定鍵名的屬性列表。

  3. 當我傳入以下鍵["key1", "key2", "faultyKey"] ,我希望我的函數返回一個空列表。

我的命令式解決方案看起來像這樣,它可以正常工作:

private List<AttributeEntity> getAttributeEntities(List<String> keys, Document value) {
    final List<AttributeEntity> documentAttributeList = value.getAttributeEntityList();
    final List<AttributeEntity> resultList = new ArrayList<>();

    for(String configKey: keys){
        boolean keyInAttribute = false;
        for(AttributeEntity documentAttribute : documentAttributeList){
            if(configKey.equals(documentAttribute.getAttribute_key())){
                keyInAttribute = true;
                resultList.add(documentAttribute);
                break;
            }
        }
        if(!keyInAttribute){
            resultList.clear();
            break;
        }
    }

    return resultList;
}

對於教育和娛樂(也許更好的擴展),我想知道如何使用新的Java 8 streaming-api將這段代碼轉換為解決方案。


這就是我想到的,將我的Java8前代碼轉換為Java8。

在我看來,它看起來更簡潔,而且更短。 但它沒有,我期望它做什么:/

我真的很難實現我的要求的第三個要點。 它總是返回所有(找到的)屬性,即使我傳入一個不存在的鍵。

private List<AttributeEntity> getAttributeEntities(List<String> keys, Document value) {
    final List<AttributeEntity> documentAttributeList = value.getAttributeList();

    return documentAttributeList.stream()
            .filter(attribute ->
                    keys.contains(attribute.getAttribute_key())
            ).collect(Collectors.toList());
}

我正在考慮實現自己的自定義收集器。 由於我的收集器只應返回List,因為收集的結果至少包含一次給定的鍵。

關於如何實現這一目標的任何其他想法?


這個解決方案通過我的測試 但感覺就像我把車放在馬前。

它既不簡潔也不簡短或優雅。

private List<AttributeEntity> getAttributeEntities(List<String> keys, Document value) {
    final List<AttributeEntity> documentAttributeList = value.getAttributeList();

    return documentAttributeList.stream()
            .filter(attribute ->
                            keys.contains(attribute.getAttribute_key())
            )
            .collect(Collectors.collectingAndThen(Collectors.toList(), new Function<List<AttributeEntity>, List<AttributeEntity>>() {
                @Override
                public List<AttributeEntity> apply(List<AttributeEntity> o) {
                    System.out.println("in finisher code");
                    if (keys.stream().allMatch(key -> {
                        return o.stream().filter(attrbiute -> attrbiute.getAttribute_key().equals(key)).findAny().isPresent();
                    })) {
                        return o;
                    } else {
                        return new ArrayList<AttributeEntity>();
                    }
                }
            }));
}

首先,我必須說我也是Java 8新功能的新手,所以我對一切都不熟悉,而且不習慣函數式編程。 我嘗試了一種不同的方法,將其全部划分為一些方法。

這里是:

public class Main {

    private static List<AttributeEntity> documentAttributeList;

    static {
        documentAttributeList = new ArrayList<>();
        documentAttributeList.add(new AttributeEntity("key1", "value1"));
        documentAttributeList.add(new AttributeEntity("key2", "value2"));
        documentAttributeList.add(new AttributeEntity("key3", "value3"));
    }

    public static void main(String[] args) {
        Main main = new Main();
        List<AttributeEntity> attributeEntities = main.getAttributeEntities(Arrays.asList("key1", "key2"));
        for (AttributeEntity attributeEntity : attributeEntities) {
            System.out.println(attributeEntity.getKey());
        }
    }

    private List<AttributeEntity> getAttributeEntities(List<String> keys) {
        if(hasInvalidKey(keys)){
            return new ArrayList<>();
        } else {
            return documentAttributeList.stream().filter(attribute -> keys.contains(attribute.getKey())).collect(toList());
        }
    }

    private boolean hasInvalidKey(List<String> keys) {
        List<String> attributeKeys = getAttributeKeys();
        return keys.stream().anyMatch(key -> !attributeKeys.contains(key));
    }

    private List<String> getAttributeKeys() {
        return documentAttributeList.stream().map(attribute -> attribute.getKey()).collect(toList());
    }

}

如果一個文檔永遠不會有多個具有相同名稱的屬性,我認為你可以這樣做(沒有編譯器方便嘗試):

Map<String, AttributeEntity> filteredMap=value.getAttributeEntityList().stream()
    .filter(at->keys.contains(at.getKey()))
    .collect(toMap(at->at.getKey(), at->at));

return filteredMap.keySet().containsAll(keys) 
    ? new ArrayList<>(filteredMap.values()) 
    : new ArrayList<>();

如果允許每個名稱包含多個屬性,則必須使用groupingBy而不是toMap。 當然,你可以用collectAndThen重寫它,但我認為它不太清楚。

我想出了一些東西。

我不知道它是否是最優雅的解決方案,但至少它是有效的,我可以推理它。

private List<AttributeEntity> getAttributeEntities(List<String> keys, Document value) {
    final List<AttributeEntity> documentAttributeList = value.getAttributeList();

    boolean allKeysPresentInAnyAttribute = keys.stream()
            .allMatch(key ->
                    documentAttributeList.stream()
                            .filter(attrbiute ->
                                    attrbiute.getAttribute_key().equals(key)
                            )
                            .findAny()
                            .isPresent()
            );
    if (allKeysPresentInAnyAttribute) {
        return documentAttributeList.stream()
                .filter(attribute ->
                    keys.contains(attribute.getAttribute_key())
                )
                .collect(Collectors.toList());
    }
    return new ArrayList<>();
}

任何提示或評論都非常感謝。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM