英文:
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" +
"}" +
"]";
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论