亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Java 函數式編程:如何將 for 循環中的 if-else 階梯轉換為函數式風格?

Java 函數式編程:如何將 for 循環中的 if-else 階梯轉換為函數式風格?

暮色呼如 2023-03-31 16:46:42
期望是從輸入列表中派生 3 個列表itemIsBoth,,。如何將下面的代碼轉換為功能樣式?(我知道這段代碼在命令式風格中已經足夠清晰了,但我想知道聲明式風格是否真的無法處理這樣一個簡單的例子)。謝謝。aItemsbItemsitemsfor (Item item: items) {    if (item.isA() && item.isB()) {        itemIsBoth.add(item);    } else if (item.isA()) {        aItems.add(item);    } else if (item.isB()){        bItems.add(item)    }}
查看完整描述

5 回答

?
MMMHUHU

TA貢獻1834條經驗 獲得超8個贊

問題標題相當廣泛(轉換 if-else 階梯),但由于實際問題詢問的是特定場景,所以讓我提供一個示例,至少可以說明可以做什么。


因為該if-else結構基于應用于項目的謂詞創建了三個不同的列表,所以我們可以將此行為更明確地表達為分組操作。要開箱即用,唯一需要做的額外工作是使用標記對象折疊多個布爾謂詞。例如:


class Item {

    enum Category {A, B, AB}


    public Category getCategory() {

        return /* ... */;

    }

}

那么邏輯可以簡單的表達為:


Map<Item.Category, List<Item>> categorized = 

    items.stream().collect(Collectors.groupingBy(Item::getCategory));

其中每個列表都可以從給定類別的地圖中檢索。


如果無法更改 class Item,則可以通過移動 enum 聲明和分類方法使其超出類Item(該方法將成為靜態方法)來實現相同的效果。


查看完整回答
反對 回復 2023-03-31
?
一只萌萌小番薯

TA貢獻1795條經驗 獲得超7個贊

另一種使用 Vavr 并只對項目列表進行一次迭代的解決方案可以使用以下方法實現foldLeft:


list.foldLeft(

    Tuple.of(List.empty(), List.empty(), List.empty()), //we declare 3 lists for results

    (lists, item) -> Match(item).of(

        //both predicates pass, add to first list

        Case($(allOf(Item::isA, Item::isB)), lists.map1(l -> l.append(item))),

        //is a, add to second list

        Case($(Item::isA), lists.map2(l -> l.append(item))),

        //is b, add to third list

        Case($(Item::isB), lists.map3(l -> l.append(item)))

    ))

);

它將返回一個包含三個結果列表的元組。


查看完整回答
反對 回復 2023-03-31
?
慕森王

TA貢獻1777條經驗 獲得超3個贊

既然你提到了 vavr 作為標簽,我將提供一個使用 vavr 集合的解決方案。


import static io.vavr.Predicates.allOf;

import static io.vavr.Predicates.not;


...


final Array<Item> itemIsBoth = items.filter(allOf(Item::isA,     Item::isB));

final Array<Item> aItems     = items.filter(allOf(Item::isA, not(Item::isB)));

final Array<Item> bItems     = items.filter(allOf(Item::isB, not(Item::isA)));

該解決方案的優點是簡單易懂,一目了然,而且它的功能與 Java 一樣。缺點是它將遍歷原始集合三次而不是一次。這仍然是一個O(n),但乘數為 3。在非關鍵代碼路徑和小型集合中,為了代碼清晰度而犧牲幾個 CPU 周期可能是值得的。


當然,這也適用于所有其他 vavr 集合,因此您可以替換Array為List、Vector、Stream等。


查看完整回答
反對 回復 2023-03-31
?
慕運維8079593

TA貢獻1876條經驗 獲得超5個贊

擺脫 the 的另一種方法if-else是將它們替換為Predicateand Consumer:


Map<Predicate<Item>, Consumer<Item>> actions = 

  Map.of(item.predicateA(), aItems::add, item.predicateB(), bItems::add);

actions.forEach((key, value) -> items.stream().filter(key).forEach(value));

因此,您需要增強Item這兩種方法predicateA()并使用您在和predicateB()中實現的邏輯isA()isB()


順便說一句,我仍然建議使用你的if-else邏輯。


查看完整回答
反對 回復 2023-03-31
?
侃侃爾雅

TA貢獻1801條經驗 獲得超16個贊

當然可以。功能方式是使用聲明方式。


在數學上你正在設置一個Equivalence relation,然后,你可以寫


Map<String, List<Item>> ys = xs

    .stream()

    .collect(groupingBy(x -> here your equivalence relation))

一個簡單的例子說明了這一點


public class Main {


    static class Item {

        private final boolean a;

        private final boolean b;


        Item(boolean a, boolean b) {

            this.a = a;

            this.b = b;

        }


        public boolean isB() {

            return b;

        }


        public boolean isA() {

            return a;

        }

    }


    public static void main(String[] args) {

        List<Item> xs = asList(new Item(true, true), new Item(true, true), new Item(false, true));

        Map<String, List<Item>> ys = xs.stream().collect(groupingBy(x -> x.isA() + "," + x.isB()));

        ys.entrySet().forEach(System.out::println);

    }

}

帶輸出


true,true=[com.foo.Main$Item@64616ca2, com.foo.Main$Item@13fee20c]

false,true=[com.foo.Main$Item@4e04a765]


查看完整回答
反對 回復 2023-03-31
  • 5 回答
  • 0 關注
  • 174 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號