【问题标题】:Dynamic dictionary recursion in Python3Python3中的动态字典递归
【发布时间】:2018-03-21 22:42:38
【问题描述】:

我在这方面工作太久了,需要一些帮助。 我正在尝试使用faker创建字典。要是就这么简单就好了。 最初字典是扁平的。钥匙和物品。如果键的第一个字母是“B”或“M”,它将将该字符串转换为具有 5 个键的字典并继续执行此操作,直到找不到以这两个字母中的任何一个开头的字母。我知道,现在没有递归发生。这就是我需要帮助的原因。我试图弄清楚如何正确递归而不是硬编码深度。

Starting Dictionary:
{
     "Marcia": "https://www.skinner.biz/categories/tags/terms.htm",
     "Nicholas": "https://scott-tran.com/",
     "Christopher": "https://www.ellis.com/",
     "Paul": "https://lopez.com/index/",
     "Jennifer": "https://www.sosa.com/wp-content/main/login.php"
}

Marcia 应该扩展到这个...

Example:
    "Marcia": {
        "Alexander": "http://hicks.net/home.html",
        "Barry": {
            "Jared": "https://www.parker-robinson.com/faq.html",
            "Eddie": "https://www.smith-thomas.com/",
            "Ryan": "https://www.phillips.org/homepage/",
            "Mary": {
               "Alex": "http://www.perry.com/tags/explore/post.htm",
               "Joseph": "https://www.hansen.com/main/list/list/index/",
               "Alicia": "https://www.tran.biz/wp-content/explore/posts/",
               "Anna": "http://lee-mclaughlin.biz/search/login/",
               "Kevin": "https://blake.net/main/index/"
            }
           "Evan": "http://carroll.com/homepage.html"
        }
        "Sharon": "https://www.watson.org/categories/app/login/",
        "Hayley": "https://www.parks.com/",
        "William": "https://www.wyatt-ware.com/"
    }

我的代码是手动的而不是动态的,因为我现在必须明确知道字典的许多层次,而不是动态地找出它。

这是我拥有的 2 个级别的深度,但我想找到任何以“B”或“M”开头的键并对其进行操作。

import json
from build_a_dictionary import add_dic
from faker import Faker

dic = add_dic(10)
dic1 = {}
dic2 = {}

def build_dic(dic_len):
  dic1 = {}
  fake = Faker()
  if len(dic1) == 0:
    dic1 = add_dic(dic_len)
  print(json.dumps(dic1, indent=4))
  for k, v in dic1.items():
    dic2[k] = add_dic(dic_len)
    for key in dic2[k].keys():
      for f in key:
        if f == 'B' or f == 'M':
          dic2[k][key] = add_dic(dic_len)
  return dic2

这是我写的 add_dic() 的代码:

import string, time
from faker import Faker  #had to install with pip
fake = Faker()
dic = {}
dics = {}
key = ""
def add_dic(x):
  dic={}
  start = time.time()
  if x > 690:
    print("Please select a value under 690")
    sys.exit()
  for n in range(x):
    while len(dic) < x:
      key = fake.first_name()
      if key in dic.keys():
        break
      val = fake.uri()
      dic[key] = val
  end = time.time()
  runtime = end - start
  return dic

【问题讨论】:

  • 嵌套名称从何而来?
  • 字典中的所有数据都来自 add_dic()。

标签: python recursion


【解决方案1】:

您只是做错了,如果您希望它是递归的,请将函数编写为递归函数。它本质上是字典的自定义(递归)映射函数。至于您期望的字典,我不确定您如何让Faker 每次都确定性地为您提供相同的输出。这是随机的......

注意:这没有什么“动态”的,它只是一个递归映射函数。

from faker import Faker
import pprint

pp = pprint.PrettyPrinter(indent=4)
fake = Faker()

def map_val(key, val):
    if key[0] == 'M' or key[0] == 'B':
        names = [(fake.first_name(), fake.uri()) for i in range(5)]
        return {k : map_val(k, v) for k,v in names}
    else:
        return val

#uncomment below to generate 5 initial names
#names = [(fake.first_name(), fake.uri()) for i in range(5)]
#initial_dict = {k : v for k,v in names}

initial_dict = {
     "Marcia": "https://www.skinner.biz/categories/tags/terms.htm",
     "Nicholas": "https://scott-tran.com/",
     "Christopher": "https://www.ellis.com/",
     "Paul": "https://lopez.com/index/",
     "Jennifer": "https://www.sosa.com/wp-content/main/login.php"
}

dict_2 = {k : map_val(k,v) for k,v in initial_dict.items()}

pp.pprint(dict_2)

输出:

rpg711$ python nested_dicts.py 

{   'Christopher': 'https://www.ellis.com/',
    'Jennifer': 'https://www.sosa.com/wp-content/main/login.php',
    'Marcia': {   'Chelsea': 'http://francis.org/category.jsp',
                  'Heather': 'http://www.rodgers.com/privacy.jsp',
                  'Jaime': 'https://bates-molina.com/register/',
                  'John': 'http://www.doyle.com/author.htm',
                  'Kimberly': 'https://www.harris.org/homepage/'},
    'Nicholas': 'https://scott-tran.com/',
    'Paul': 'https://lopez.com/index/'
}

【讨论】:

  • 谢谢rpg711。我只是在这里练习,所以获得相同的数据并不重要,但是如果你向 faker 添加种子值,它每次都会给出相同的数据。我真的需要研究你的 return 语句和对 map_val 的调用。我想写更多这样的代码。哦,填充“名称”很酷。我会用这种风格写一些东西——甚至可能是这个。
【解决方案2】:

感谢大家的帮助。我已经设法弄清楚了。 它现在可以根据需要构建动态字典或动态 json。

import sys, json
from faker import Faker
fake = Faker()

def build_dic(dic_len, dic):
  if isinstance(dic, (list, tuple)):
    dic = dict(dic)
  if isinstance(dic, dict):
    for counter in range(len(dic)):
      for k,v in dic.items():
        if k[0] == 'B' or k[0] == "M":
          update = [(fake.first_name(), fake.uri()) for i in range(5)]
          update = dict(update)
          dic.update({k: update})
  return dic

def walk(dic):
  for key, item in dic.items():
      #print(type(item))
      if isinstance(item, dict):
        build_dic(5, item)
        walk(item)
  return dic

a = build_dic(10, ([(fake.first_name(), fake.uri()) for i in range(10)]))
walk(a)
print(json.dumps(a, indent=4))

【讨论】:

    【解决方案3】:

    递归是函数调用自身的时候;在设计递归函数时,记住退出条件(即递归何时停止)很重要。

    让我们考虑一个人为的例子来增加一个数字直到它达到某个值:

    def increment_until_equal_to_or_greater_than_value(item, target):
        print 'item is', item,
        if item < target:
            print 'incrementing'
            item += 1
            increment_until_equal_to_or_greater_than_value(item, target)
        else:
            print 'returning'
            return item
    
    
    increment_until_equal_to_or_greater_than_value(1, 10)
    

    还有输出

    item is 1 incrementing
    item is 2 incrementing
    item is 3 incrementing
    item is 4 incrementing
    item is 5 incrementing
    item is 6 incrementing
    item is 7 incrementing
    item is 8 incrementing
    item is 9 incrementing
    item is 10 returning
    

    您可以看到我们在if 语句中定义了递归部分,在else 中定义了退出条件。

    我整理了一个 sn-p,它显示了嵌套数据结构上的递归函数。

    它并不能完全解决您的问题,这样您可以通过剖析它并使其适合您的用例来学习。

    # our recursive method
    def deep_do_something_if_string(source, something):
        # if source is a dict, iterate through it's values
        if isinstance(source, dict):
            for v in source.itervalues():
                # call this method on the value
                deep_do_something_if_string(v, something)
    
        # if source is a list, tuple or set, iterate through it's items
        elif isinstance(source, (list, tuple, set)):
            for v in source:
                deep_do_something_if_string(v, something)
    
        # otherwise do something with the value
        else:
            return something(source)
    
    
    # a test something to do with the value
    def print_it_out(value):
        print value
    
    
    # an example data structure
    some_dict = {
        'a': 'value a',
        'b': [
            {
                'c': 'value c',
                'd': 'value d',
            },
        ],
        'e': {
            'f': 'value f',
            'g': {
                'h': {
                    'i': {
                        'j': 'value j'
                    }
                }
            }
        }
    }
    
    deep_do_something_if_string(some_dict, print_it_out)
    

    还有输出

    value a
    value c
    value d
    value j
    value f
    

    【讨论】:

    • 哎呀,在 python 中使用 isinstance 是一个禁忌,除非在极少数情况下。
    • 这是一个有趣的观察,我不知道 - 你能帮我理解为什么吗?
    • 检查动态类型语言中的类型通常是不好的做法,尤其是在 Python 中是非 Python 的。动态类型语言的全部意义在于类型无关紧要,python 解释器只关心对象的名称……首先为使用这种语言提供了很大的力量。作为一个具体示例,请参见:stackoverflow.com/questions/17028722/…
    • 顺便说一句,仅仅因为一个对象在python中属于某种类型并不意味着它与该类型的引用对象是相同的对象“类型”(至少,不像您会期望使用静态类型的语言),因为 python 支持将名称动态绑定到实例。
    • 那么在我使用递归函数发布的示例中,正确的方法是什么?简单的for x in thing 不适用于字典和列表/集/元组,至于字典它只会迭代键,但同时列表等没有itervalues() 我应该是@ 987654330@ 或其他决定如何迭代它?
    猜你喜欢
    • 2020-11-05
    • 2017-02-16
    • 2012-11-11
    • 1970-01-01
    • 1970-01-01
    • 2021-07-22
    • 2020-06-10
    • 2012-11-11
    • 2017-01-23
    相关资源
    最近更新 更多