You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何高效合并Java中List<FinalValue>为单个FinalValue对象?

Solution for Merging List into a Single FinalValue

Hey, let's tackle this merging problem properly. Instead of writing messy nested loops manually, we can leverage Java Stream API plus custom merging logic to make the code cleaner, more readable, and maintainable. First, let's clarify the class structure with necessary additions (getters, setters, and equals/hashCode are critical for merging):

import java.math.BigDecimal;
import java.util.*;

class FinalValue {
    private List<Item> items;
    private List<Option> options;

    // Getters and Setters
    public List<Item> getItems() { return items; }
    public void setItems(List<Item> items) { this.items = items; }
    public List<Option> getOptions() { return options; }
    public void setOptions(List<Option> options) { this.options = options; }

    static class Item {
        private String itemId;
        private Type type;
        private Rate rate;
        private String currency;

        // Getters and Setters
        public String getItemId() { return itemId; }
        public void setItemId(String itemId) { this.itemId = itemId; }
        public Type getType() { return type; }
        public void setType(Type type) { this.type = type; }
        public Rate getRate() { return rate; }
        public void setRate(Rate rate) { this.rate = rate; }
        public String getCurrency() { return currency; }
        public void setCurrency(String currency) { this.currency = currency; }

        // Equals and HashCode for deduplication
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Item item = (Item) o;
            return Objects.equals(itemId, item.itemId) && Objects.equals(type, item.type) && Objects.equals(rate, item.rate) && Objects.equals(currency, item.currency);
        }

        @Override
        public int hashCode() {
            return Objects.hash(itemId, type, rate, currency);
        }
    }

    static class Option {
        private String optionId;
        private Type type;
        private Rate rate;
        private String currency;

        // Getters and Setters
        public String getOptionId() { return optionId; }
        public void setOptionId(String optionId) { this.optionId = optionId; }
        public Type getType() { return type; }
        public void setType(Type type) { this.type = type; }
        public Rate getRate() { return rate; }
        public void setRate(Rate rate) { this.rate = rate; }
        public String getCurrency() { return currency; }
        public void setCurrency(String currency) { this.currency = currency; }

        // Equals and HashCode for deduplication
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Option option = (Option) o;
            return Objects.equals(optionId, option.optionId) && Objects.equals(type, option.type) && Objects.equals(rate, option.rate) && Objects.equals(currency, option.currency);
        }

        @Override
        public int hashCode() {
            return Objects.hash(optionId, type, rate, currency);
        }
    }

    static class Rate {
        private Integer id;
        private BigDecimal rateAmount;
        private Boolean isActive;

        // Getters and Setters
        public Integer getId() { return id; }
        public void setId(Integer id) { this.id = id; }
        public BigDecimal getRateAmount() { return rateAmount; }
        public void setRateAmount(BigDecimal rateAmount) { this.rateAmount = rateAmount; }
        public Boolean getIsActive() { return isActive; }
        public void setIsActive(Boolean isActive) { this.isActive = isActive; }

        // Equals and HashCode for grouping/deduplication
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Rate rate = (Rate) o;
            return Objects.equals(id, rate.id) && Objects.equals(rateAmount, rate.rateAmount) && Objects.equals(isActive, rate.isActive);
        }

        @Override
        public int hashCode() {
            return Objects.hash(id, rateAmount, isActive);
        }
    }

    enum Type {
        TYPE_A, TYPE_B // Add your actual enum values here
    }
}

Core Merging Logic

The approach follows three key steps:

  1. Collect all nested Item/Option objects from every FinalValue in the list
  2. Group them by their unique identifier (e.g., itemId for Item, optionId for Option)
  3. Merge each group using your rule: keep one instance if most entries agree, keep all unique variations if there's disagreement

Step 1: Generic Helper Methods

First, let's create reusable utilities to handle frequency counting and consistency checks:

import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

// Get the most frequent value from a frequency map
private static <T> T getMajorityValue(Map<T, Long> frequencyMap) {
    return frequencyMap.entrySet().stream()
            .max(Map.Entry.comparingByValue())
            .map(Map.Entry::getKey)
            .orElse(null);
}

// Check if all entries in a frequency map have the same value (no disagreements)
private static <T> boolean hasSingleValue(Map<T, Long> frequencyMap) {
    return frequencyMap.size() == 1;
}

Step 2: Merge Item Groups

Now implement the merging logic for Item lists (the Option logic will be nearly identical):

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

// Merge all items from multiple FinalValue objects
private static List<FinalValue.Item> mergeItems(List<FinalValue.Item> allItems) {
    return allItems.stream()
            // Group items by their unique itemId
            .collect(Collectors.groupingBy(FinalValue.Item::getItemId))
            .values().stream()
            // Merge each group of items with the same itemId
            .map(ItemMerger::mergeItemGroup)
            // Flatten the list of merged groups (each group might return 1 or multiple items)
            .flatMap(List::stream)
            .collect(Collectors.toList());
}

// Merge a group of items with the same itemId
private static List<FinalValue.Item> mergeItemGroup(List<FinalValue.Item> itemGroup) {
    // Count frequency of each attribute in the group
    Map<FinalValue.Type, Long> typeFreq = itemGroup.stream()
            .collect(Collectors.groupingBy(FinalValue.Item::getType, Collectors.counting()));
    Map<FinalValue.Rate, Long> rateFreq = itemGroup.stream()
            .collect(Collectors.groupingBy(FinalValue.Item::getRate, Collectors.counting()));
    Map<String, Long> currencyFreq = itemGroup.stream()
            .collect(Collectors.groupingBy(FinalValue.Item::getCurrency, Collectors.counting()));

    // Check if all attributes are consistent across the group
    boolean allConsistent = hasSingleValue(typeFreq) && hasSingleValue(rateFreq) && hasSingleValue(currencyFreq);

    if (allConsistent) {
        // All items in the group are identical: return one instance
        return Collections.singletonList(itemGroup.get(0));
    } else {
        // There are disagreements: return all unique attribute combinations
        return itemGroup.stream()
                .distinct()
                .collect(Collectors.toList());
    }
}

Step 3: Merge Option Groups

Copy the Item merging logic and adjust for Option (replace Item with Option and itemId with optionId):

private static List<FinalValue.Option> mergeOptions(List<FinalValue.Option> allOptions) {
    return allOptions.stream()
            .collect(Collectors.groupingBy(FinalValue.Option::getOptionId))
            .values().stream()
            .map(OptionMerger::mergeOptionGroup)
            .flatMap(List::stream)
            .collect(Collectors.toList());
}

private static List<FinalValue.Option> mergeOptionGroup(List<FinalValue.Option> optionGroup) {
    Map<FinalValue.Type, Long> typeFreq = optionGroup.stream()
            .collect(Collectors.groupingBy(FinalValue.Option::getType, Collectors.counting()));
    Map<FinalValue.Rate, Long> rateFreq = optionGroup.stream()
            .collect(Collectors.groupingBy(FinalValue.Option::getRate, Collectors.counting()));
    Map<String, Long> currencyFreq = optionGroup.stream()
            .collect(Collectors.groupingBy(FinalValue.Option::getCurrency, Collectors.counting()));

    boolean allConsistent = hasSingleValue(typeFreq) && hasSingleValue(rateFreq) && hasSingleValue(currencyFreq);

    if (allConsistent) {
        return Collections.singletonList(optionGroup.get(0));
    } else {
        return optionGroup.stream()
                .distinct()
                .collect(Collectors.toList());
    }
}

Step 4: Merge the Entire List of FinalValue

Tie everything together to merge the full list into one FinalValue object:

import java.util.List;
import java.util.stream.Collectors;

public static FinalValue mergeFinalValues(List<FinalValue> finalValues) {
    // Collect all items from all FinalValue objects
    List<FinalValue.Item> allItems = finalValues.stream()
            .map(FinalValue::getItems)
            .flatMap(List::stream)
            .collect(Collectors.toList());

    // Collect all options from all FinalValue objects
    List<FinalValue.Option> allOptions = finalValues.stream()
            .map(FinalValue::getOptions)
            .flatMap(List::stream)
            .collect(Collectors.toList());

    // Merge items and options
    List<FinalValue.Item> mergedItems = mergeItems(allItems);
    List<FinalValue.Option> mergedOptions = mergeOptions(allOptions);

    // Create the merged FinalValue object
    FinalValue mergedFinalValue = new FinalValue();
    mergedFinalValue.setItems(mergedItems);
    mergedFinalValue.setOptions(mergedOptions);

    return mergedFinalValue;
}

Customization Notes

  • Adjust "Majority" Definition: If you need "majority" to mean more than 50% (not just most frequent), modify getMajorityValue to check if the top frequency exceeds itemGroup.size() / 2.
  • Generate Full Attribute Combinations: If "keep all possible values" means creating every combination of differing attributes (instead of keeping unique original items), replace the distinct() step with code to generate a Cartesian product of all unique attribute values.
  • Strategy Pattern: For maximum flexibility, encapsulate different merging rules into separate strategy classes (e.g., ConsistentMergeStrategy, FullVariationMergeStrategy) and switch them as needed.

内容的提问来源于stack exchange,提问作者Amit

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:32:03