Java 8中的GroupingBy流具有3个以上的分组级别

dxpyg8gm  于 5个月前  发布在  Java
关注(0)|答案(2)|浏览(55)

我需要像下面这样生成一个输出JSON

{
   "account":{
      "Alpha":{
         "OLD":{
            "long":"zerozerooneO",
            "short":"001O"
         },
         "NEW":{
            "long":"zerozerooneN",
            "short":"001N"
         }
      },
      "Beta":{
         "OLD":{
            "long":"zerozerooneO",
            "short":"001O"
         },
         "NEW":{
            "long":"zerozerooneN",
            "short":"001N"
         }
      }
   }
}

字符串
从下面的对象列表中获取示例

[
   {
      "codetype":"Alpha",
      "shortOldCode":"001O",
      "longOldCode":"zerozerooneO",
      "shortNewCode":"001N",
      "longNewCode":"zerozerooneN"
   },
   {
      "codetype":"Beta",
      "shortOldCode":"001O",
      "longOldCode":"zerozerooneO",
      "shortNewCode":"001N",
      "longNewCode":"zerozerooneN"
   }
]


我试过这样的方法

Map<String, Map<String, Map<String, List<Object>>>> newList = new HashMap<>();
            newList = dataMap.stream()
                    .filter(distinctByKey(code -> code.getCodeType())).collect(
                            groupingBy((GetCodeTypes a) -> "account",
                                    groupingBy((GetCodeTypes b) -> b.getCodeType(),
                                            groupingBy((GetCodeTypes c) -> "OLD",
                                                    mapping(
                                                            v -> {
                                                                GetCodeTypesResponse.Old
oldCode = new GetCodeTypesResponse.Old();
                                                                oldCode.setLongs(v.getLongOldCode());
                                                                oldCode.setShorts(v.getShortOldCode());
                                                                return oldCode;
                                                            }, toList())))));


希望任何人都能给我指出一个正确的方向,在Java 8中使用hashmap来获得所需的输出。我知道使用记录进行分组/Map可能适用于新版本的Java,但我正在做的项目是Java 1.8,如果可能的话,我想使用Java Streams来解决这个问题。

wz1wpwve

wz1wpwve1#

这里有一个合理的,但不基于流的解决方案来解决你的问题:

package com.learn.grouping;

import com.fasterxml.jackson.annotation.JsonProperty;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

/**
 * This is the format of your input JSON
 */
@Getter
@Setter
@ToString(doNotUseGetters = true)
public class BlamItemInput
{
    @JsonProperty("codetype")
    private String codeType;

    private String longNewCode;
    private String longOldCode;
    private String shortNewCode;
    private String shortOldCode;
}

package com.learn.grouping;

import java.util.List;

import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Component;

/**
 * This converts from input format to desired output (layered map) format.
 */
@Component
public class BlamConverter
{
    public CodeTypeMap convert(final List<BlamItemInput> blamItemInputList)
    {
        final CodeTypeMap returnValue;

        if (CollectionUtils.isNotEmpty(blamItemInputList))
        {
            returnValue = new CodeTypeMap();

            for (final BlamItemInput current : blamItemInputList)
            {
                final KapowItem kapowItem = new KapowItem();

                kapowItem.setNewItem(current.getLongNewCode(), current.getShortNewCode());
                kapowItem.setOldItem(current.getLongOldCode(), current.getShortOldCode());

                returnValue.addKapowItem(current.getCodeType(), kapowItem);
            }
        }
        else
        {
            returnValue = null;
        }

        return returnValue;
    }
}

package com.learn.grouping;

import java.util.HashMap;
import java.util.Map;

import com.fasterxml.jackson.annotation.JsonProperty;

import lombok.Getter;
import lombok.ToString;

/**
 * Top level of the output format
 */
@Getter
@ToString(doNotUseGetters = true)
public class CodeTypeMap
{
    @JsonProperty("account")
    private final Map<String, KapowItem> kapowMap = new HashMap<>();

    public void addKapowItem(
        final String keyValue,
        final KapowItem newCodeTypeItem)
    {
        kapowMap.put(keyValue, newCodeTypeItem);
    }
}

package com.learn.grouping;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;

import lombok.Getter;
import lombok.ToString;

/**
 * Second level of the output JSON
 */
@Getter
@ToString(doNotUseGetters = true)
@JsonPropertyOrder({"OLD", "NEW"})
public class KapowItem
{
    @JsonProperty("NEW")
    private KapowNestedItem newItem;

    @JsonProperty("OLD")
    private KapowNestedItem oldItem;

    public void setNewItem(
        final String longValue,
        final String shortValue)
    {
        newItem = new KapowNestedItem(longValue, shortValue);
    }

    public void setOldItem(
        final String longValue,
        final String shortValue)
    {
        oldItem = new KapowNestedItem(longValue, shortValue);
    }
}

package com.learn.grouping;

import com.fasterxml.jackson.annotation.JsonProperty;

import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.ToString;

/**
 * Bottom (third) level of the output JSON
 */
@Getter
@RequiredArgsConstructor
@ToString(doNotUseGetters = true)
public class KapowNestedItem
{
    @JsonProperty("long")
    private final String longValue;

    @JsonProperty("short")
    private final String shortValue;
}

package com.learn.grouping;

import java.util.List;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;

import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.type.TypeFactory;

/**
 * Converter unit test because, you aren't done until after you unit test.
 */
@ExtendWith(MockitoExtension.class)
public class TestBlamConverter
{
    private static final String INPUT_JSON = "[{\"codetype\":\"Alpha\",\"shortOldCode\":\"001O\",\"longOldCode\":\"zerozerooneO\",\"shortNewCode\":\"001N\",\"longNewCode\":\"zerozerooneN\"},{\"codetype\":\"Beta\",\"shortOldCode\":\"001O\",\"longOldCode\":\"zerozerooneO\",\"shortNewCode\":\"001N\",\"longNewCode\":\"zerozerooneN\"}]";

    private BlamConverter classToTest;

    private ObjectMapper objectMapper;

    @BeforeEach
    void beforeEach()
    {
        final Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();

        builder.featuresToDisable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,
            SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,
            SerializationFeature.FAIL_ON_EMPTY_BEANS);

        builder.serializationInclusion(Include.NON_NULL);

        objectMapper = builder.build();

        classToTest = new BlamConverter();
    }

    @Test
    void convert_allGood_succes() throws JsonMappingException, JsonProcessingException
    {
        final CodeTypeMap actualResult;
        final List<BlamItemInput> inputList;
        final String outputJson;
        final TypeFactory typeFactory = objectMapper.getTypeFactory();

        inputList = objectMapper.readValue(INPUT_JSON, typeFactory.constructCollectionType(List.class, BlamItemInput.class));

        actualResult = classToTest.convert(inputList);

        outputJson = objectMapper.writeValueAsString(actualResult);

        System.out.println("outputJson: " + outputJson);
    }
}

字符串

yfwxisqw

yfwxisqw2#

这是一个简单的非流解决方案,使用JSON库进行转换。
https://github.com/octomix/josson

Josson josson = Josson.fromJsonString("[{\"codetype\":\"Alpha\",\"shortOldCode\":\"001O\",\"longOldCode\":\"zerozerooneO\",\"shortNewCode\":\"001N\",\"longNewCode\":\"zerozerooneN\"},{\"codetype\":\"Beta\",\"shortOldCode\":\"001O\",\"longOldCode\":\"zerozerooneO\",\"shortNewCode\":\"001N\",\"longNewCode\":\"zerozerooneN\"}]");
JsonNode node = josson.getNode(
    "map(codetype::" +
    "    map(OLD:" +
    "        map(long: longOldCode," +
    "            short: shortOldCode)," +
    "        NEW:" +
    "        map(long: longNewCode," +
    "            short: shortNewCode)" +
    "    )" +
    ")" +
    ".mergeObjects()" +
    ".toObject('account')");
System.out.println(node.toPrettyString());

字符串

输出

{
  "account" : {
    "Alpha" : {
      "OLD" : {
        "long" : "zerozerooneO",
        "short" : "001O"
      },
      "NEW" : {
        "long" : "zerozerooneN",
        "short" : "001N"
      }
    },
    "Beta" : {
      "OLD" : {
        "long" : "zerozerooneO",
        "short" : "001O"
      },
      "NEW" : {
        "long" : "zerozerooneN",
        "short" : "001N"
      }
    }
  }
}

相关问题