在功能上添加到数组列表中的唯一随机对象

时间:2018-02-25 12:12:16

标签: java functional-programming refactoring

public Hand dealHand(int endExclusive) {
        List<Card> randomCardsCreated = IntStream.range(0, endExclusive).
        mapToObj(i -> {
            Card randomCard = generateRandomCard();

            while (this.cardsDealt.contains(randomCard)) {
                randomCard = generateRandomCard();
            }
            return randomCard;
        }).
        collect(Collectors.toList());

        this.cardsDealt.addAll(randomCardsCreated);

        return Hand.hand(randomCardsCreated);
}

我有这种方法,它生成一张随机卡并将其添加到字段列表(cardsDealt)。它还确保randomCard不在列表中,如果是,它将生成一个新的随机卡。然后它将创建一个x卡列表以添加到cardsDealt中,然后它将创建一个包含cardsDealt的新Hand对象。我认为这是不言自明的。

我想摆脱randomCard的可变性,而不是改变randomCard我想在功能上做到这一点,但到目前为止还没有成功。 我也试图摆脱while循环并使用流。

任何建议都会有所帮助。感谢。

修改

根据以下评论,这里有更多信息。

以下是如何使用上述代码的更多代码。

public List<PlayerResult> playGame(Player... players) {
        List<Player> playersWithAHandOfCards = dealHandToAllPlayers(players);
        ...
}

private List<Player> dealHandToAllPlayers(Player[] players) {
        return Arrays.stream(players).map(this::dealHand).collect(Collectors.toList());
}

private Player dealHand(Player player) {
        Hand hand = deck.dealHand(5);
        return player(player.playerName, hand);
}

代码在我的github https://github.com/hanfak/poker-game

编辑2:

我已经用程序格式重写了这个方法,它看起来不错,采取了列出所有卡片的建议,洗牌并选择前5张牌作为牌并将其从牌组中移除。

更多信息。 Rank和Suit只是枚举,Card类包含Rank和Suit的构造函数,以及重写的equals和hashcode方法。手和卡是使用静态工厂方法创建的。

private final List<Rank> ranks = Arrays.asList(Rank.values());
private final List<Suit> suits = Arrays.asList(Suit.values());
private List<Card> deck = createDeck();

public Hand dealHand(int endExclusive) {
        Collections.shuffle(deck);

        List<Card> dealtCards = getHand(endExclusive);

        deck = deck.stream()
            .filter(card -> !dealtCards.contains(card))
            .collect(Collectors.toList());

        return Hand.hand(dealtCards);
    }

private List<Card> getHand(int endExclusive) {
        if(deck.size() >= 5) {
            return deck.subList(0, endExclusive);
        } else {
            throw new IllegalArgumentException("Not enough cards left over");
        }
    }

private List<Card> createDeck() {
        List<Card> deck = new ArrayList<>();
        for(Rank rank : ranks) {
            for(Suit suit : suits) {
                deck.add(Card.card(rank, suit));
            }
        }
        return deck;
    }

如果可以将其转换为功能样式,我仍然会感激,我不喜欢使用Collections.shuffle(套牌)而且不能使用final来进行字段&#39; deck&#39;。

1 个答案:

答案 0 :(得分:1)

如果你想使用函数式编程,你几乎就在那里 - 你只需要考虑一些小的改动。

  • 在您制作的信息流中,不是使用Stream.range运行endExclusive次,而是generate无限流而limit到{{1} }}?它是一个int,它正是写入限制方法的东西的类型。

  • 而不是在while循环中运行以确保您的随机卡不在已发卡中 - 如何在流中使用EndExclusive本地执行此操作?

简而言之,我的代码建议是:

filter

public Hand dealHand(int endExclusive) { List<Card> randomCardsCreated = Stream.generate(()->generateRandomCard()).distinct(). filter(i->!cardsDealt.contains(i)).limit(endExclusive). collect(Collectors.toList()); this.cardsDealt.addAll(randomCardsCreated); return Hand.hand(randomCardsCreated); } - 生成无限的随机卡流。

Stream.generate(()->generateRandomCard())过滤当前手中的所有重复卡片(原始代码中未处理的问题)。

distinct()删除已经处理过的任何卡片。

filter(i->!cardsDealt.contains(i))将结果限制在手中的endExclusive卡片。

这对您的实施有用吗?