当前位置: 首页 > 知识库问答 >
问题:

如何使用Java过滤器lambda对Arraylist元素进行分组

晏经武
2023-03-14

我试图按Java数组列表元素分组。

我有一个JSONObjects数组,如下所示,我想按字段price和side分组,然后将股票与新字段buyShares和sellShares相加

    [{"shares":20,"side":"B","orderId":"001","price":"500"}, 
    {"shares":20,"side":"S","orderId":"002","price":"501"}, 
    {"shares":25,"side":"B","orderId":"003","price":"500"}, 
    {"shares":10,"side":"S","orderId":"004","price":"501"}, 
    {"shares":30,"side":"B","orderId":"005","price":"505"}, 
    {"shares":35,"side":"B","orderId":"006","price":"505"}, 
    {"shares":35,"side":"S","orderId":"007","price":"500"}]

我想按价格和侧边分组,得到如下所示:

[{"price":"500","buyShares":45, "sellShares":35}, {"sellShares":30,"price":"501"}, {"price":"505","buyShares":65}]

我使用以下Java代码:

ArrayList<JSONObject> aOrdersArray = new ArrayList<>(aOrders.values());
System.out.println(aOrdersArray);
List<JSONObject> test = aOrdersArray.stream()
        .distinct()
        .collect(Collectors.groupingBy(jsonObject -> jsonObject.getInt("price")))
        .entrySet().stream()
        .map(e -> e.getValue().stream()
        .reduce((f1,f2) -> {
            JSONObject h = new JSONObject();
            h.put("price",f1.get("price"));
            System.out.println(f1);
            if (f1.get("side").equals("B") && f2.get("side").equals("B")) {
                h.put("buyShares", f1.getInt("shares") + f2.getInt("shares"));
            }
            else if (f1.get("side").equals("S") && f2.get("side").equals("S")) {
                h.put("sellShares", f1.getInt("shares") + f2.getInt("shares"));
            }
            else if (f1.get("side").equals("S")) {
                h.put("sellShares", f1.get("shares"));
            }
            else if (f1.get("side").equals("B")) {
                h.put("buyShares",f1.get("shares"));
            }
            else if (f2.get("side").equals("S")) {
                h.put("sellShares", f2.get("shares"));
            }
            else if (f2.get("side").equals("B")) {
                h.put("buyShares",f2.get("shares"));
            }
            return h;
        }))
        .map(f -> f.get())
        .collect(Collectors.toList());
System.out.println(test);

有时会出现以下错误

Exception in thread "main" org.json.JSONException: JSONObject["side"] not found.

共有2个答案

司空凌
2023-03-14

要使用gson,可以创建一个类:

public class Share{
    private int shares;
    private String side;
    private String orderId;
    private String price;
    
    //getters and setters
    public int getShares() {
        return shares;
    }

    public void setShares(int shares) {
        this.shares = shares;
    }

    public String getSide() {
        return side;
    }

    public void setSide(String side) {
        this.side = side;
    }

    public String getOrderId() {
        return orderId;
    }

    public void setOrderId(String orderId) {
        this.orderId = orderId;
    }

    public String getPrice() {
        return price;
    }

    public void setPrice(String price) {
        this.price = price;
    }
}

然后您可以使用这个从JSON映射object:

 String yourJson = "[{\"shares\":20,\"side\":\"B\",\"orderId\":\"001\",\"price\":\"500\"},{\"shares\":35,\"side\":\"S\",\"orderId\":\"007\",\"price\":\"500\"}]";
 Gson gson = new Gson();
 Type shareListType = new TypeToken<ArrayList<Share>>(){}.getType();
 ArrayList<Share> userArray = gson.fromJson(yourJson, shareListType);  
贺桐
2023-03-14

你试图做的事情是复杂和容易出错的,因为你的开始是错误的。

您首先就不应该有 。JSON输入中的数据是常规的,您希望对其内容进行操作。

正确的开始方法是创建一个表示这样一条记录的Java对象,然后将JSON输入转换为正确的,惯用的Java版本。你想要:

@Value class Record {
  int shares;
  RecordKind kind;
  int orderId;
  int price;

  public PriceGroup toGroup() {
    return new PriceGroup(price,
      kind == BUY ? shares : 0,
      kind == SELL ? shares : 0);
  }
}

@Value class PriceGroup {
  int price;
  int buyShares;
  int sellShares;

  public PriceGroup merge(PriceGroup other) {
    if (other.price != this.price) throw new IllegalArgumentException();
    return new PriceGroup(price,
      this.buyShares + other.buyShares,
      this.sellShares + other.sellShares);
  }
}

注意:使用Lombok's的 。假设这个东西有一个构造函数,所有字段都是final,toString和equals以及hashCode都在正确的位置,等等。

一旦您拥有了上述两种类型,那么您就可以将您的输入JSON转换为一个 list<record> ode=""> 。有了这个 /code>之后,您才应该开始映射,分组等。

当然,该错误将永远不会发生,并且您的MAP/GROUP代码将更容易阅读。您所做的任何错别字都将导致编译时错误。自动完成将工作良好,等等:所有的优点。

要将JSON转换为给定类型,请使用jackson。如果您不想添加该依赖项(确实应该添加),那么在Record类中编写一个 方法,并使用 立即获取记录对象流,而不要返回到JSONObject。

List<Record> orders = ...;
List<PriceGroup> test = orders.stream()
        .distinct()
        .map(Record::toGroup)
        .collect(Collectors.groupingBy(PriceGroup::getPrice))
        .entrySet().stream()
        .map(e -> e.getValue().stream()
        .reduce((f1, f2) -> f1.merge(f2))
        .collect(Collectors.toList());

您的代码现在非常容易阅读,所有方法都有正确的名称(它是 ,而不是 ),并且可以通过自动完成等方式发现,例如,您可以单独测试 功能

 类似资料:
  • 问题内容: 我有一个属于每个小组的球员名单。如何使用过滤器列出每个组的用户? 我在寻找这个结果: team alpha Gene team beta George Paula team gamma Steve Scruath of the 5th sector 问题答案: 可以使用angular.filter模块的groupBy。 因此您可以执行以下操作: JS: HTML: 结果: Group

  • 我想使用流API过滤包含哈希映射的数组列表。 上述方法给出了结果列表。现在,我想通过一些条件过滤这个列表,并收集一个新的哈希映射数组列表。 例如,我想选择具有“null”值且字符串具有“parent_item_id”的哈希映射。 我尝试了以下方法。 最后,它起作用了 我用了这个谢谢大家

  • 如何使用匹配数组的多个值从集合中获取对象。例如:我收集了以下数据

  • 问题内容: 有人可以给我看一个简单的示例,如何使用新的lambda语法在Java 8中按字母顺序排序。 问题答案: 对于字符串,这将工作

  • 问题内容: 假设我有一个类似的元组: 我想过滤出列表并生成一个以’img’开头的元素的新列表。因此,我的新列表将如下所示: 谢谢! 问题答案: 单程: 另一种方式: 第一种称为列表理解。有关相关技术,请参见FC的答案。基本语法为。它在语义上等效于以下内容: 该位是可选的,就像在for循环中一样。 第二个是简单的内置函数,它接受测试函数和可迭代函数,并返回一个包含“通过”测试函数的每个元素的列表。,

  • 因此,我有一个,下面的字符串作为元素: null null

  • 问题内容: 我有一个,我想在一行中过滤掉负值(创建一个没有新数组)而不添加循环。使用Java 8 Lambda表达式是否可能? 在python中,将使用生成器: 是否可以在Java 8中做类似的简洁操作? 问题答案: 是的,您可以通过在数组中创建一个,滤除负片,然后将流转换回数组来实现此目的。这是一个例子: 如果要过滤不是的引用数组,则需要使用采用的方法来获取原始类型的数组作为结果:

  • 我创建了一个To-Do-List程序,记录用户输入的任务。对于每个任务,用户必须输入名称、日期等。 当用户从菜单中选择“5”时,程序会按这些任务的日期对它们进行排序。我需要根据任务的日期和时间的升序对所有任务进行排序,即日期和时间较早的任务会排在日期和时间较晚的任务之前,并显示排序后的列表。 然而,当我运行代码时,我会收到以下错误: 下面是我到目前为止的代码:(在底部)