简体   繁体   English

Javascript中递归函数的记忆

[英]Memoization of a recursive function in Javascript

I have this recursive function that takes in an array of deck cards and finds the index of the certain card:我有这个递归函数,它接收一组卡片并找到特定卡片的索引:

const getCardIndex = (deck, fullCardName) => fullCardName === deck[0] ? 52 - deck.length : getCardIndex(deck.splice(1), fullCardName)

const deck = 'Ace of Hearts, Ace of Diamonds, Ace of Clubs, Ace of Spades, Two of Hearts, Two of Diamonds, Two of Clubs, Two of Spades, Three of Hearts, Three of Diamonds, Three of Clubs, Three of Spades, Four of Hearts, Four of Diamonds, Four of Clubs, Four of Spades, Five of Hearts, Five of Diamonds, Five of Clubs, Five of Spades, Six of Hearts, Six of Diamonds, Six of Clubs, Six of Spades, Seven of Hearts, Seven of Diamonds, Seven of Clubs, Seven of Spades, Eight of Hearts, Eight of Diamonds, Eight of Clubs, Eight of Spades, Nine of Hearts, Nine of Diamonds, Nine of Clubs, Nine of Spades, Ten of Hearts, Ten of Diamonds, Ten of Clubs, Ten of Spades, Jack of Hearts, Jack of Diamonds, Jack of Clubs, Jack of Spades, Queen of Hearts, Queen of Diamonds, Queen of Clubs, Queen of Spades, King of Hearts, King of Diamonds, King of Clubs, King of Spades'.split(', ')

const result = getCardIndex(deck, 'King of Spades')

console.log(result)

Is there any way it can be sped-up, ie using memoization?有什么办法可以加快速度,即使用记忆?

As the comments suggest, there is little reason to do this recursively.正如评论所暗示的那样,几乎没有理由递归地执行此操作。 indexOf solves this problem nicely. indexOf很好地解决了这个问题。

But, if you're determined to write a recursive solution, there is a huge problem with your technique.但是,如果您决定编写递归解决方案,则您的技术存在巨大问题。 You are destroying the object you are trying to search!您正在破坏您要搜索的对象!

Array.prototype.splice is destructive . Array.prototype.splice破坏性的 It alters the array it works on.它改变了它处理的数组。 In the end, you'll have an index and a nearly-empty deck of cards!最后,您将拥有一个索引和一副几乎为空的纸牌!

That this works at all is almost coincidence.这完全有效几乎是巧合。 If perhaps you meant to use slice , that would work and not have this problem.如果您打算使用slice ,那会起作用并且不会出现此问题。 slice simply gives you a copy of the array starting from one index and ending at another (or at the end of the array.) splice does more. slice只是为您提供从一个索引开始并在另一个索引(或数组末尾)结束的数组副本。 splice做的更多。 It removes a sub-list of element, inserts additional ones and the returns the removed ones.它删除元素的子列表,插入额外的元素并返回删除的元素。 If you happen to call it with just a starting index, it removes the rest of the array and returns it.如果你碰巧只用一个起始索引调用它,它会删除数组的其余部分并返回它。 So the calls deck.slice(1) and deck.splice(1) happen to return the same thing, but the second one also removes all the returned items from your array.所以调用deck.slice(1)deck.splice(1)碰巧返回相同的东西,但第二个也从你的数组中删除了所有返回的项目。

So the quickest fix to your function is simply this:因此,对您的函数的最快修复就是这样:

const getCardIndex = (deck, fullCardName) => 
  fullCardName === deck[0] 
    ? 52 - deck.length 
    : getCardIndex (deck.slice(1), fullCardName)

But this makes little sense, honestly.但这没什么意义,老实说。 It works, but on every recursive call, it builds a new array, one shorter than the previous version.它可以工作,但在每次递归调用时,它都会构建一个新数组,比以前的版本短。 That's a lot of memory for a simple search.对于简单的搜索来说,这是很多内存。

So here's another technique that recurses only on the index:所以这是另一种仅在索引上递归的技术:

const getCardIndex = (deck, fullCardName, idx = 0) =>
  idx >= deck.length 
    ? -1
    : deck [idx] == fullCardName
      ? idx
      : getCardIndex (deck, fullCardName, idx + 1)

Note, however that there is nothing in this specific to decks and cards except the names of the variables and the function.但是请注意,除了变量和函数的名称之外,没有任何特定于甲板和卡片的内容。 So we could convert this to a more generic function like this:因此,我们可以将其转换为更通用的函数,如下所示:

const getIndex = (xs, x, idx = 0) =>
  idx >= xs.length 
    ? -1
    : xs [idx] == x
      ? idx
      : getIndex (xs, x, idx + 1)

And there we have a recursive solution for finding the index of a value in an arbitrary array.我们有一个递归解决方案,用于在任意数组中查找值的索引。

Again, though, there is very little reason to use this function.不过,再次说明,几乎没有理由使用此功能。 It's a reasonable exercise for learning about recursion, but not much else.这是学习递归的合理练习,但除此之外别无他法。 Use indexOf instead.改用indexOf

For a solution that identifies the solutions in advance ( O(52) = O(1) ) and then can look up solutions in a single operation, ditch the recursive function, turn the deck into an object, whose keys are card names and values are card indicies, and then just look up the card property on the object:对于预先确定解决方案( O(52) = O(1) )然后可以在单个操作中查找解决方案的解决方案,抛弃递归函数,将牌组变成一个对象,其键是卡片名称和值是卡片索引,然后只需查找对象上的卡片属性:

 const deck = 'Ace of Hearts, Ace of Diamonds, Ace of Clubs, Ace of Spades, Two of Hearts, Two of Diamonds, Two of Clubs, Two of Spades, Three of Hearts, Three of Diamonds, Three of Clubs, Three of Spades, Four of Hearts, Four of Diamonds, Four of Clubs, Four of Spades, Five of Hearts, Five of Diamonds, Five of Clubs, Five of Spades, Six of Hearts, Six of Diamonds, Six of Clubs, Six of Spades, Seven of Hearts, Seven of Diamonds, Seven of Clubs, Seven of Spades, Eight of Hearts, Eight of Diamonds, Eight of Clubs, Eight of Spades, Nine of Hearts, Nine of Diamonds, Nine of Clubs, Nine of Spades, Ten of Hearts, Ten of Diamonds, Ten of Clubs, Ten of Spades, Jack of Hearts, Jack of Diamonds, Jack of Clubs, Jack of Spades, Queen of Hearts, Queen of Diamonds, Queen of Clubs, Queen of Spades, King of Hearts, King of Diamonds, King of Clubs, King of Spades'.split(', ') const deckObj = Object.fromEntries(deck.map((str, i) => [str, i])); console.log(deckObj['King of Spades']) console.log(deckObj['Ace of Diamonds']) console.log(deckObj['Queen of Diamonds'])

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM