Рекурсивное чтение данных Python - PullRequest
5 голосов
/ 07 марта 2012

Следующее будет иметь больше смысла, если вы когда-либо играли в майнкрафт. Поскольку многие из вас этого не сделали, я постараюсь объяснить это как можно лучше

Я пытаюсь написать рекурсивную функцию, которая может найти шаги для создания любого предмета майнкрафта из набора файлов рецептов майнкрафта. Это меня действительно поставило в тупик.

Плоский файл довольно длинный, поэтому я включил его в этот список.

def getRecipeChain(item, quantity=1):
    #magic recursive stuffs go here

Так что, в основном, мне нужно посмотреть первый рецепт, затем поискать рецепты для всех компонентов этого первого рецепта и так далее, пока не дойдете до предметов без рецептов. Каждый раз, когда мне нужно добавить рецепт в список, я получаю некий набор инструкций о порядке создания предметов.

Итак, вот функция, которая у меня есть сейчас (та, которая не работает)

def getRecipeChain(name, quantity=1):
    chain = []

    def getRecipe(name1, quantity1=1):
        if name1 in recipes:
            for item in recipes[name1]["ingredients"]["input"]:
                if item in recipes:
                    getRecipe(item, quantity1)
                else:
                    chain.append(item)

    getRecipe(name, quantity)
    return chain

Вот идеальный выход, к которому я иду. Это словарь, в котором хранится название товара и количество.

>>> getRecipeChain("solar_panel", 1):
{"insulated_copper_cable":13, "electronic_circuit":2, "re_battery":1, "furnace":1, "machine":1, "generator":1, "solar_panel":1}

Итак, вопрос в том, как мне это сделать?

Я знаю, что вопрос о том, чтобы люди работали для вас, нахмурился, поэтому, если вы чувствуете, что это слишком близко к вам, просто пишите мне код, просто скажите.

Ответы [ 2 ]

3 голосов
/ 07 марта 2012

Это может быть элегантно решено с помощью collections.Counter, который поддерживает сложение:

from collections import Counter

def getRecipe(name, quantity=1):
  if not name in recipes: return Counter({name: quantity})

  subitems = recipes[name]["ingredients"]["input"]
  return sum((getRecipe(item, quantity) for item in subitems), 
             Counter())

print repr(dict(getRecipe("solar_panel")))
# => {'copper': 39, 'refined_iron': 10, 'glass': 3, 
#     'rubber': 78, 'cobblestone': 8, 'tin': 4, 
#     'coal_dust': 3, 'nothing': 10, 'redstone': 6}
1 голос
/ 07 марта 2012

Я думаю, что проблема в 2 раза. Прежде всего, вам нужно добавлять элементы в цепочку в рекурсивном вызове getRecipe (). Во-вторых, я думаю, что две функции бесполезно усложняют вещи. Я думаю, что только внутренний должен сделать. Нечто подобное это то, что вы ищете. Я не проверял его, но он должен быть достаточно близко, чтобы вы могли начать на правильном пути.

def getRecipe(name, quantity=1):
    chain=[];
    if name in recipes:
        for item in recipes[name]["ingredients"]["input"]:
            if item in recipes:
                chain.append(getRecipe(item, quantity))
            else:
                chain.append(item)
    return chain

РЕДАКТИРОВАТЬ: комментарии заполняют мое отсутствие знаний Python, так что вот лучшее решение.

from collections import Counter
def getRecipe(name, quantity=1, count=Counter()):
    if name in recipes:
        for item in recipes[name]["ingredients"]["input"]:
            if item in recipes:
                getRecipe(item, quantity,counter)
            else:
                counter[item]+=quantity
    return counter
...