簡體   English   中英

按 2 級深度屬性在列表中查找重復項

[英]Find duplicates in List by 2 level deep property

我不確定如何稱呼 2 層深的屬性。

但是假設我們有List<FruitColor> ,其中FruitColor是 2 個實體。 (這些都是示例實體)一個fruit可以有不同的color ,但是color也可以有不同的fruit

public class FruitColor {
    private String fruitColorId;
    private Fruit fruit;
    private Color color;
    private int ripe; //1 to 3 where 1 unripe 2 normal 3 ripe

    // more props, getters, etc.
}

public class Fruit {
    private String fruitId;
    private String fruitName;

    // getters, etc.
}

public class Color {
    private String colorId;
    private String colorName;

    // getters, etc.
}

我在考慮以下步驟:

  1. fruitName過濾所有重復項
  2. 選擇兩個“副本”之一。 我說“重復”是因為它們只有相同的name ,但color不同。 選擇保留哪一個的規則是季節/時間轉換指示器systemTransition ,它由范圍從0100double屬性systemTransition描述。
  3. 刪除其他“重復項”。
  4. 如果有重復,則使水果的成熟度降低0.5
  5. 設置factorialRipeness ,它是ripe * systemTransitionripe * (100 - systemTransition)取決於我們在這個季節有多遠,一半是閾值。
  6. 返回具有正確Color的建議FruitColors ,按FactorialRipeness排序 問題是,這可能可以通過很多 for 循環來實現,但我只是想知道是否有更有效的方法。

我確實找到了有關如何按屬性過濾的來源,但此解決方案不允許我過濾屬性(= fruitName )的屬性。 Java 8 按屬性區分

我制作了一個有效的代碼示例(同樣是不同的實體)。 有沒有可以提高效率的部分? 我的意思是更高效,如果代碼可以更短和/或更快。 稍后我肯定會將該方法重構為更小的部分。 抱歉造成混亂,如果不使用完全相同的實體,這個問題真的很難解釋。

//logic in the method
{   
    List<FruitColor> fruitColors = getAllFCs();
    
    //Remove if FC is neither colors that were chosen
    fruitColors.removeIf(fc -> fc.getColor().getColorId() != presentColor.getColor().getColorId()
            && fc.getColor().getColorId() != futureColor.getColor().getColorId());
    List<FruitColor> suggestedFruits = new ArrayList<>();

    //Systemtransition is the season/time from 0 to 100, where 100 the fruit should be completely ripe with the corresponding color.
    //If the time is less than half, it should pick the present color, which is the less ripe color.
    boolean getPresentColorFruit = systemTransition < 50;

    // --->This whole for-if-if-else-elseif-if-else part I wanted to make more "efficient" <---
    for (FruitColor fruitColor : fruitColors) {
        //First check for duplicate FCs 
        List<FruitColor> sameNameFruits = fruitColors.stream()
                .filter(fc -> fc.getFruit().getName().equals(itemColor.getFruit().getName()))
                .collect(Collectors.toList());
                
        //If there is only one of the fruit, check if it's added already. If not, than add with proper ripeness
        //FactorialRipeness is the "true" ripeness.
        if (sameNameFruits.size() == 1 && !suggestedFruits.stream().anyMatch(fc -> fc.getFruit().getName().equals(sameNameFruits.get(0).getFruit().getName()))) {
            FruitColor onlyOne = sameNameFruits.get(0);
            if (onlyOne.getColor().getColorId() == presentColor.getColor().getColorId()) {
                onlyOne.setFactorialRipeness(onlyOne.getRipeness() * systemTransition);
            } else {
                onlyOne.setFactorialRipeness(onlyOne.getRipeness() * (100 - systemTransition));
            }
            suggestedFruits.add(onlyOne);
          // If there are multiple FCs, than the ripeness has to go down. Which prioritizes duplicate FCs more. (this part isn't logical with these entities, sorry)
        } else if(!suggestedFruits.stream().anyMatch(fc -> fc.getFruit().getName().equals(sameNameFruits.get(0).getFruit().getName()))){
            if (getPresentColorFruit) {
                FruitColor fcWithPresentColor = sameNameFruits.stream()
                        .filter(fc -> fc.getColor().getColorId() == presentColor.getColor().getColorId()).findFirst()
                        .get();
                fcWithPresentColor.setFactorialRipeness((fcWithPresentColor.getRipeness() - 0.5) * systemTransition);
                suggestedFruits.add(fcWithPresentColor);
            } else {
                FruitColor fcWithFutureColor = sameNameFruits.stream()
                        .filter(fc -> fc.getColor().getColorId() == futureColor.getColor().getColorId()).findFirst()
                        .get();
                //This part is also not logical, but if the presentColor is not chosen. Than we need to multiply by the opposite amount of the systemTransition
                fcWithFutureColor.setFactorialRipeness((fcWithFutureColor.getRipeness() - 0.5) * (100 - systemTransition)); 
                suggestedFruits.add(fcWithFutureColor);
            }
        }
    }
    //Sort by "true" ripeness value, from lowest to highest
    Collections.sort(suggestedFruits, new FruitColorRipenessComparator());
    return suggestedFruits;
}

/**
 * @source https://stackoverflow.com/questions/2839137/how-to-use-comparator-in-java-to-sort
 */
public class FruitColorRipenessComparator implements Comparator<FruitColor> {
    @Override
    public int compare(FruitColor a, FruitColor b){
        return a.getFactorialRipeness() < b.getFactorialRipeness() ? -1 : a.getFactorialRipeness() == b.getFactorialRipeness() ? 0 : 1;
    }
}

作為一個可能的選項,您可以通過將FruitColor實例存儲到Map中,按其fruitname屬性對實例進行分組。 然后將值轉儲到列表中。

它可以通過 Stream API 使用 Collector toMap(keyMapper,valueMapper,mergeFunction)來實現。

選擇保留哪一個的規則是水果的成熟程度,從 0 到 100,這是水果的一個屬性

要實現mergeFunction ,這意味着解析映射到相同鍵的值,我們可以使用 static 方法BinaryOpearator.maxBy() ,它需要一個Comparator

比較FruitColor實例的基於rape屬性的fruit字段的比較器可以用以下方式表示:

Comparator.comparingInt(fruitColor -> fruitColor.getFruit().getRipe())

或者作為:

Comparator.comparing(
    FruitColor::getFruit,
    Comparator.comparingInt(Fruit::getRipe)
)

整體實現可能如下所示:

List<FruitColor> fruitColors = // initializing the list
        
List<FruitColor> fruitColorsDistinct = fruitColors.stream()
    .collect(Collectors.toMap(
        fruitColor -> fruitColor.getFruit().getFruitName(), // keyMapper
        Function.identity(),  // valueMapper
        BinaryOperator.maxBy( // mergeFunction - resolving duplicates
            Comparator.comparingInt(fruitColor -> fruitColor.getFruit().getRipe())
        )
    ))
    .values().stream()
    .toList();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM