英文:
Filtering JSon using GSON and lambda
问题
[
  {
    "containertype": "check2",
    "item": [
      {
        "d1": "Pt"
      }
    ],
    "contenttype": "test"
  }
]
public class Testing {
    public static void main(String[] args) {
       
        try {
            final String json = "[{\"containertype\":\"check2\",\"item\":[{\"d1\":\"St\"},{\"d1\":\"Pt\"},{\"d1\":\"St\"}],\"contenttype\":\"test\"},{\"containertype\":\"check2\",\"item\":[{\"d1\":\"St\"},{\"d1\":\"St\"},{\"d1\":\"st\"}],\"contenttype\":\"test\"}]";
            Gson gson = new Gson();
            Type rowListType = new TypeToken<List<Map<String, Object>>>() {
            }.getType();
            final List<Map<String, Object>> rows = gson.fromJson(json, rowListType);
            rows.forEach(row -> {
                if (row.containsKey("item")) {
                    List<Map<String, String>> items = (List<Map<String, String>>) row.get("item");
                    items.removeIf(item -> "St".equals(item.get("d1")));
                    if (items.isEmpty()) {
                        rows.remove(row);
                    }
                }
            });
            System.out.println(gson.toJson(rows, rowListType));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
英文:
I have huge json of the below sample format . I want to filter all items where "d1" equals "St" . I want to delete that object also in case no items are left because of above filtering .
[
{
  "containertype": "check2",
  "item": [
    {
      "d1": "St"
    },
    {
      "d1": "Pt"
    },
    {
      "d1": "St"
    }
  ],
  "contenttype": "test"
},
{
  "containertype": "check2",
  "item": [
    {
      "d1": "St"
    },
    {
      "d1": "St"
    },
    {
      "d1": "st"
    }
  ],
  "contenttype": "test"
}
]
Expected Result
[
{
  "containertype": "check2",
  "item": [
    
    {
      "d1": "Pt"
    }
  ],
  "contenttype": "test"
}
]
This is what i have tried , i am reading the json , using Gson , i got the map now i am trying to filter the items where the condition is met . :
    public class Testing {
public static void main(String[] args) {
   
    try {
        final String json = "[{"containertype":"check2","item":[{"d1":"St"},{"d1":"Pt"},{"d1":"St"}],"contenttype":"test"},{"containertype":"check2","item":[{"d1":"Pt"},{"d1":"Pt"},{"d1":"Pt"}],"contenttype":"test"}]";
         Gson gson = new Gson();
        Type rowListType = new TypeToken<List<Map<String, Object>>>() {
        }.getType();
final List<Map<String, Object>> rows = gson.fromJson(json, rowListType);
            rows.stream()
                    .filter(r -> r.containsKey("item"))
                    .collect(Collectors.toList());
            System.out.println(gson.toJson(rows, rowListType));
    } catch (Exception e) {
        e.printStackTrace();
    }
}
}
答案1
得分: 2
以下是翻译好的代码部分:
## 定义一些POJO类
JSON应该被读取/反序列化为一些对象。因此,*Gson*(或者Jackson)被称为**映射器**。它们将JSON映射到POJO(普通的Java对象)。
所以让我们定义模型。
为了简单起见,使用了Lombok(构造函数,getter/setter,toString)。
### Item
```java
import lombok.Data;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@Data
public class Item {
    private String d1;
}
Container(包含items)
此外,使用了Gson的注解来遵守Java命名约定(驼峰命名法),同时允许您指定的字段名称(小写)。
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@NoArgsConstructor
public class Container {
    @SerializedName("containertype")
    private String containerType;
    @SerializedName("item")
    private List<Item> items;
    @SerializedName("contenttype")
    private String contentType;
}
向服务类添加功能
将一些JSON映射到容器
使用Type引用让Gson知道要创建哪些对象。
Type containerListType = new TypeToken<ArrayList<Container>>(){}.getType();
gson = new Gson();
List<Container> containerList = gson.fromJson(json, containerListType);
过滤出具有匹配指定条件的items的容器
使用functional Predicate和streaming(Java 8):
    public static Predicate<Item> itemWhereD1equalsSt = item -> "St".equals(item.getD1());
    public static Predicate<Container> containerHasItemsWhereD1equalsSt = container -> {
        List<Item> items = container.getItems();
        if (items != null) {
            boolean hasItemMatching = items.stream().anyMatch(itemWhereD1equalsSt);
            return hasItemMatching;
        }
        return false;
    };
    public List<Container> filterFromJson(List<Container> containerList, Predicate<Container> containerPredicate) {
        return containerList.stream()
                .filter(containerPredicate)
                .collect(Collectors.toList());
    }
删除匹配指定条件的items
使用List的stream-based和functional便捷方法(Java 8):
(a) 简单的变体(在lambda表达式中内联使用predicate):
    public void removeItemsSimple(List<Container> containers) {
        for (Container container : containers) {
            container.getItems().removeIf(item -> item.getD1().equalsIgnoreCase("St"));
        }
    }
(b) 增强的变体(将已经与容器一起使用的predicate作为参数传递):
    public List<Item> removeItemsBasedOnFilter(List<Container> containers, Predicate<Item> itemPredicate) {
        return containers.stream()
                .flatMap(container -> removeItemsBasedOnFilter(container, itemPredicate).stream())
                .collect(Collectors.toList());
    }
    public List<Item> removeItemsBasedOnFilter(Container container, Predicate<Item> itemPredicate) {
        // 可选:过滤容器中应该被删除的所有items
        List<Item> itemsToBeRemoved = container.getItems().stream()
                .filter(itemPredicate)
                .collect(Collectors.toList());
        // 删除与predicate匹配的所有items
        container.getItems().removeIf(itemPredicate);
        // 可选:返回已删除的items
        return itemsToBeRemoved;
    }
完整的服务类
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public class JsonFilter {
    private static final Type containerListType = new TypeToken<ArrayList<Container>>(){}.getType();
    public static Predicate<Item> itemWhereD1equalsSt = item -> "St".equals(item.getD1());
    public static Predicate<Container> containerHasItemsWhereD1equalsSt = container -> {
        List<Item> items = container.getItems();
        if (items != null) {
            boolean hasItemMatching = items.stream().anyMatch(itemWhereD1equalsSt);
            return hasItemMatching;
        }
        return false;
    };
    private final Gson gson;
    public JsonFilter() {
        gson = new Gson();
    }
    public List<Container> readContainers(String json) {
        List<Container> containerList = gson.fromJson(json, containerListType);
        return containerList;
    }
    public List<Container> filterFromJson(List<Container> containerList, Predicate<Container> containerPredicate) {
        return containerList.stream()
                .filter(containerPredicate)
                .collect(Collectors.toList());
    }
    public void removeItemsSimple(List<Container> containers) {
        for (Container container : containers) {
            container.getItems().removeIf(item -> item.getD1().equalsIgnoreCase("St"));
        }
    }
    public List<Item> removeItemsBasedOnFilter(List<Container> containers, Predicate<Item> itemPredicate) {
        return containers.stream()
                .flatMap(container -> removeItemsBasedOnFilter(container, itemPredicate).stream())
                .collect(Collectors.toList());
    }
    public List<Item> removeItemsBasedOnFilter(Container container, Predicate<Item> itemPredicate) {
        // 可选:过滤容器中应该被删除的所有items
        List<Item> itemsToBeRemoved = container.getItems().stream()
                .filter(itemPredicate)
                .collect(Collectors.toList());
        // 删除与predicate匹配的所有items
        container.getItems().removeIf(itemPredicate);
        // 可选:返回已删除的items
        return itemsToBeRemoved;
    }
}
已测试
使用JUnit5进行测试,没有断言 - 只是打印到控制台。
import org.junit.jupiter.api.Test;
import java.util.List;
class JsonFilterTest {
    @Test
    void filterContainerList() {
        final String json = givenJson(); // 您的测试数据
        final JsonFilter jsonFilter = new JsonFilter();
        // 将JSON映射到容器列表
        List<Container> containersRead = jsonFilter.readContainers(json);
        // 首先过滤掉所有不具有指定items的容器
        List<Container> containersFiltered = jsonFilter.filterFromJson(containersRead, JsonFilter.containerHasItemsWhereD1equalsSt);
        System.out.println("Filtered containers resulting: " + containersFiltered.size());
        // 然后从这些结果容器中删除指定的items
        List<Item> itemsRemoved = jsonFilter.removeItemsBasedOnFilter(containersFiltered, JsonFilter.itemWhereD1equalsSt);
        System
<details>
<summary>英文:</summary>
## Define some POJO classes
JSON is meant to be read/deserialized into some objects. Thus *Gson* (or alternatively Jackson) called **mapper**. They map JSON to POJO (plain old Java objects).
So let's define the model.
For simplicity used Lombok (constructors, getter/setter, toString). 
### Item
```java
import lombok.Data;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@Data
public class Item {
    private String d1;
}
Container (containing items)
Additionally used Gson's annotation to obey Java-naming-convention (camelCase) while allowing your specified field-names (lower-case).
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@NoArgsConstructor
public class Container {
    @SerializedName("containertype")
    private String containerType;
    @SerializedName("item")
    private List<Item> items;
    @SerializedName("contenttype")
    private String contentType;
}
Add functionality to a service-class
Map some JSON to containers
Using a Type-reference to let Gson know what objects to create.
Type containerListType = new TypeToken<ArrayList<Container>>(){}.getType();
gson = new Gson();
List<Container> containerList = gson.fromJson(json, containerListType);
Filter out containers that do have items matching the specified criterion
using a functional Predicate and streaming (Java 8):
    public static Predicate<Item> itemWhereD1equalsSt = item -> "St".equals(item.getD1());
    public static Predicate<Container> containerHasItemsWhereD1equalsSt = container -> {
        List<Item> items = container.getItems();
        if (items != null) {
            boolean hasItemMatching = items.stream().anyMatch(itemWhereD1equalsSt);
            return hasItemMatching;
        }
        return false;
    };
    public List<Container> filterFromJson(List<Container> containerList, Predicate<Container> containerPredicate) {
        return containerList.stream()
                .filter(containerPredicate)
                .collect(Collectors.toList());
    }
Remove items that match the specified criterion
Using the stream-based and functional convenience-method on List (Java 8):
(a) The simple variant (predicate inlined using lambda expression):
    public void removeItemsSimple(List<Container> containers) {
        for (Container container : containers) {
            container.getItems().removeIf(item -> item.getD1().equalsIgnoreCase("St"));
        }
    }
(b) The enhanced variant (pass as param the predicate, we used already with containers):
    public List<Item> removeItemsBasedOnFilter(List<Container> containers, Predicate<Item> itemPredicate) {
        return containers.stream()
                .flatMap(container -> removeItemsBasedOnFilter(container, itemPredicate).stream())
                .collect(Collectors.toList());
    }
    public List<Item> removeItemsBasedOnFilter(Container container, Predicate<Item> itemPredicate) {
        // Optional: filter all items in container that should be removed
        List<Item> itemsToBeRemoved = container.getItems().stream()
                .filter(itemPredicate)
                .collect(Collectors.toList());
        // remove all items that match the predicate
        container.getItems().removeIf(itemPredicate);
        // Optional: return removed items
        return itemsToBeRemoved;
    }
Complete service-class
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public class JsonFilter {
    private static final Type containerListType = new TypeToken<ArrayList<Container>>(){}.getType();
    public static Predicate<Item> itemWhereD1equalsSt = item -> "St".equals(item.getD1());
    public static Predicate<Container> containerHasItemsWhereD1equalsSt = container -> {
        List<Item> items = container.getItems();
        if (items != null) {
            boolean hasItemMatching = items.stream().anyMatch(itemWhereD1equalsSt);
            return hasItemMatching;
        }
        return false;
    };
    private final Gson gson;
    public JsonFilter() {
        gson = new Gson();
    }
    public List<Container> readContainers(String json) {
        List<Container> containerList = gson.fromJson(json, containerListType);
        return containerList;
    }
    public List<Container> filterFromJson(List<Container> containerList, Predicate<Container> containerPredicate) {
        return containerList.stream()
                .filter(containerPredicate)
                .collect(Collectors.toList());
    }
    public void removeItemsSimple(List<Container> containers) {
        for (Container container : containers) {
            container.getItems().removeIf(item -> item.getD1().equalsIgnoreCase("St"));
        }
    }
    public List<Item> removeItemsBasedOnFilter(List<Container> containers, Predicate<Item> itemPredicate) {
        return containers.stream()
                .flatMap(container -> removeItemsBasedOnFilter(container, itemPredicate).stream())
                .collect(Collectors.toList());
    }
    public List<Item> removeItemsBasedOnFilter(Container container, Predicate<Item> itemPredicate) {
        // Optional: filter all items in container that should be removed
        List<Item> itemsToBeRemoved = container.getItems().stream()
                .filter(itemPredicate)
                .collect(Collectors.toList());
        // remove all items that match the predicate
        container.getItems().removeIf(itemPredicate);
        // Optional: return removed items
        return itemsToBeRemoved;
    }
}
Tested
using JUnit5 without assertions - just printing to console.
import org.junit.jupiter.api.Test;
import java.util.List;
class JsonFilterTest {
    @Test
    void filterContainerList() {
        final String json = givenJson(); // your test-data
        final JsonFilter jsonFilter = new JsonFilter();
        // map JSON to a list of containers
        List<Container> containersRead = jsonFilter.readContainers(json);
        // first filter-out all containers that do not have specified items
        List<Container> containersFiltered = jsonFilter.filterFromJson(containersRead, JsonFilter.containerHasItemsWhereD1equalsSt);
        System.out.println("Filtered containers resulting: " + containersFiltered.size());
        // then remove specified items from these resulting containers
        List<Item> itemsRemoved = jsonFilter.removeItemsBasedOnFilter(containersFiltered, JsonFilter.itemWhereD1equalsSt);
        System.out.println("Removed items: " + itemsRemoved.size());
    }
    private String givenJson() {
        return "[\n" +
                "  {\n" +
                "    \"containertype\": \"check2\",\n" +
                "    \"item\": [\n" +
                "      {\n" +
                "        \"d1\": \"St\"\n" +
                "      },\n" +
                "      {\n" +
                "        \"d1\": \"Pt\"\n" +
                "      },\n" +
                "      {\n" +
                "        \"d1\": \"St\"\n" +
                "      }\n" +
                "    ],\n" +
                "    \"contenttype\": \"test\"\n" +
                "  },\n" +
                "  {\n" +
                "    \"containertype\": \"check2\",\n" +
                "    \"item\": [\n" +
                "      {\n" +
                "        \"d1\": \"Pt\"\n" +
                "      },\n" +
                "      {\n" +
                "        \"d1\": \"Pt\"\n" +
                "      },\n" +
                "      {\n" +
                "        \"d1\": \"Pt\"\n" +
                "      }\n" +
                "    ],\n" +
                "    \"contenttype\": \"test\"\n" +
                "  }\n" +
                "]";
    }
}
答案2
得分: 0
首先,不要显示旧的 "ROW",而是在流程之后创建的新对象。
其次,我添加了一个过滤器,在其中将 List -> Map -> 将值更改为一个项,并检查是否有其他满足条件的项。
以下是我的解决方案 -> 示例
List<Map<String, Object>> newRows = rows.stream()
        .filter(r -> r.containsKey("item"))
        .filter(r -> {
            List<Map<String, String>> item = (List<Map<String, String>>) r.get("item");
            List<Map<String, String>> newList = item.stream()
                    .filter(x -> !x.get("d1").toUpperCase().equals("ST"))
                    .collect(Collectors.toList());
            r.put("item", newList);
            return !newList.isEmpty();
        })
        .collect(Collectors.toList());
System.out.println(gson.toJson(newRows));
这是我示例的测试
我使用了你的示例进行测试
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.jetbrains.annotations.NotNull;
import org.junit.Test;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static org.junit.Assert.assertEquals;
public class GsonLambda {
  @Test
  public void test() {
    //given
    final String json = getJson();
    Gson gson = new Gson();
    Type rowListType = new TypeToken<List<Map<String, Object>>>() {
    }.getType();
    final List<Map<String, Object>> rows = gson.fromJson(json, rowListType);
    //when
    List<Map<String, Object>> newRows = rows.stream()
            .filter(r -> r.containsKey("item"))
            .filter(r -> {
                List<Map<String, String>> item = (List<Map<String, String>>) r.get("item");
                List<Map<String, String>> newList = item.stream()
                        .filter(x -> !x.get("d1").toUpperCase().equals("ST"))
                        .collect(Collectors.toList());
                r.put("item", newList);
                return !newList.isEmpty();
            })
            .collect(Collectors.toList());
    //then
    assertEquals("[{\"containertype\":\"check2\",\"item\":[{\"d1\":\"Pt\"}],\"contenttype\":\"test\"}]", gson.toJson(newRows));
  }
  @NotNull
  private String getJson() {
    return "[\n" +
            "{\"containertype\": \"check2\",\n" +
            "\"item\": [\n" +
            "{\"d1\": \"St\"},\n" +
            "{\"d1\": \"Pt\"},\n" +
            "{\"d1\": \"St\"}\n" +
            "],\n" +
            "\"contenttype\": \"test\"\n" +
            "},\n" +
            "{\"containertype\": \"check2\",\n" +
            "\"item\": [\n" +
            "{\"d1\": \"St\"},\n" +
            "{\"d1\": \"St\"},\n" +
            "{\"d1\": \"st\"}\n" +
            "],\n" +
            "\"contenttype\": \"test\"\n" +
            "}\n" +
            "]";
  }
}
英文:
first of all, don't display the old "ROW" but the new object you create after the stream
secondly, I added a filter in which I throw List -> Map-> and change the values into an item and check if there are any others that meet the criterion
below my solution -> example
List<Map<String, Object>> newRows = rows.stream()
.filter(r -> r.containsKey("item"))
.filter(r -> {
List<Map<String, String>> item = (List<Map<String, String>>) r.get("item");
List<Map<String, String>> newList = item.stream().filter(x -> !x.get("d1").toUpperCase().equals("ST")).collect(Collectors.toList());
r.put("item", newList);
return !newList.isEmpty();
})
.collect(Collectors.toList());
System.out.println(gson.toJson(newRows));
here is the test of my example
I used your example to test
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.jetbrains.annotations.NotNull;
import org.junit.Test;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static org.junit.Assert.assertEquals;
public class GsonLambda {
@Test
public void test() {
//given
final String json = getJson();
Gson gson = new Gson();
Type rowListType = new TypeToken<List<Map<String, Object>>>() {
}.getType();
final List<Map<String, Object>> rows = gson.fromJson(json, rowListType);
//when
List<Map<String, Object>> newRows = rows.stream()
.filter(r -> r.containsKey("item"))
.filter(r -> {
List<Map<String, String>> item = (List<Map<String, String>>) r.get("item");
List<Map<String, String>> newList = item.stream().filter(x -> !x.get("d1").toUpperCase().equals("ST")).collect(Collectors.toList());
r.put("item", newList);
return !newList.isEmpty();
})
.collect(Collectors.toList());
//then
assertEquals("[{\"containertype\":\"check2\",\"item\":[{\"d1\":\"Pt\"}],\"contenttype\":\"test\"}]", gson.toJson(newRows));
}
@NotNull
private String getJson() {
return "[\n" +
"{\n" +
"  \"containertype\": \"check2\",\n" +
"  \"item\": [\n" +
"    {\n" +
"      \"d1\": \"St\"\n" +
"    },\n" +
"    {\n" +
"      \"d1\": \"Pt\"\n" +
"    },\n" +
"    {\n" +
"      \"d1\": \"St\"\n" +
"    }\n" +
"  ],\n" +
"  \"contenttype\": \"test\"\n" +
"},\n" +
"{\n" +
"  \"containertype\": \"check2\",\n" +
"  \"item\": [\n" +
"    {\n" +
"      \"d1\": \"St\"\n" +
"    },\n" +
"    {\n" +
"      \"d1\": \"St\"\n" +
"    },\n" +
"    {\n" +
"      \"d1\": \"st\"\n" +
"    }\n" +
"  ],\n" +
"  \"contenttype\": \"test\"\n" +
"}" +
"]";
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论