递归修改字典

时间:2016-10-04 20:44:44

标签: python algorithm dictionary recursion

我创建了一个应该将嵌套列表转换为字典的类。以下是我的意见:

['function:and',
    ['variable:X', 'function:>=', 'value:13'],
    ['variable:Y', 'function:==', 'variable:W']]

输出应该是以下形式的字典:

{
  "function": "and",
  "args": [
    {
      "function": ">=",
      "args": [
        {
          "variable": "X"
        },
        {
          "value": 13
        }
      ]
    },
    {
      "function": "==",
      "args": [
        {
          "variable": "Y"
        },
        {
          "variable": "W"
        }
      ]
    }
  ]
}

这是接收输入列表的类,应返回所需的字典。

class Tokenizer(object):
    def __init__(self, tree):
        self.tree = tree
        self.filter = {}

    def to_dict(self, triple):
        my_dict = {}
        try:
            first = triple[0]
            second = triple[1]
            third = triple[2]
        except KeyError:
            return
        if type(second) == str and type(third) == str:
            my_dict['function'] = second.split(':')[-1]
            my_dict['args'] = [
                {first.split(':')[0]: first.split(':')[1]},
                {third.split(':')[0]: third.split(':')[1]}]
        # case recursive
        if type(second) == list:
            my_dict['function'] = first.split(':')[-1]
            my_dict['args'] = [second, third]
        return my_dict

    def walk(self, args):
        left = self.to_dict(args[0])
        right = self.to_dict(args[1])
        if isinstance(left, dict):
            if 'args' in left.keys():
                left = self.walk(left['args'])
        if isinstance(right, dict):
            if 'args' in right.keys():
                right = self.walk(right['args'])
        args = [left, right]
        return args

    def run(self):
        self.filter.update(self.to_dict(self.tree))
        if 'args' in self.filter.keys():
            self.filter['args'] = self.walk(self.filter['args'])


tree = [
    'function:and',
        ['variable:X', 'function:>=', 'value:13'],
        ['variable:Y', 'function:==', 'variable:W']
    ]

import pprint
pp = pprint.PrettyPrinter(indent=4)
t = Tokenizer(tree)
t.run()
pp.pprint(t.filter)

我的递归方法walk没有做它应该做的事情,而且我在递归时总是很傻,所以我无法弄清楚我做错了什么。

我得到的输出是:

{   'args': [[None, None], [None, None]], 'function': 'and'}

1 个答案:

答案 0 :(得分:1)

对于您的特定测试用例,您根本不需要进行递归。你可以注释掉你的电话:

import UIKit

class ViewController: UIViewController {

    var laps: [String] = []

    var minutes = 0
    var fractions = 0
    var seconds = 0
    var timer = NSTimer()
    var timerIsOn = false
    var timerString: String = ""

    @IBOutlet weak var timerLabel: UILabel!


    @IBOutlet weak var lapsTable: UITableView!

    @IBAction func startButton(sender: AnyObject) {
        if timerIsOn == false {


        fractions = 0
        seconds = 0
        minutes = 0
        timerLabel.text = "\(minutes):\(seconds).\(fractions)"
        timer = NSTimer.scheduledTimerWithTimeInterval(0.01, target: self, selector: (#selector(ViewController.updateTimer)), userInfo: nil, repeats: true)
            timerIsOn = true
        }

    }




    @IBAction func stopButton(sender: AnyObject) {
        timer.invalidate()
        timerIsOn = false
        laps.insert(timerString, atIndex: 0)
        lapsTable.reloadData()

    }

    func updateTimer(){
        fractions += 1
        if fractions == 100 {
            fractions = 0
            seconds += 1
        }
        if seconds == 60 {
            seconds = 0
            minutes += 1

        }

        timerLabel.text = "\(minutes):\(seconds).\(fractions)"

    }

    func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
        var cell = UITableViewCell(style: UITableViewCellStyle.Value1, reuseIdentifier: "Cell")

        cell.backgroundColor = self.view.backgroundColor

        cell.textLabel!.text = "Solve \(indexPath.row)"
        cell.detailTextLabel?.text = laps[indexPath.row]

        return cell

    }

    func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int {
        return laps.count


    }
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}

并获得所需的输出。 如果在输入中允许嵌套函数,则只需要进行递归:

def walk(self, args):
    left = self.to_dict(args[0])
    right = self.to_dict(args[1])
    #if isinstance(left, dict):
    #    if 'args' in left.keys():
    #        left = self.walk(left['args'])
    #if isinstance(right, dict):
    #    if 'args' in right.keys():
    #        right = self.walk(right['args'])
    args = [left, right]
    return args

然后你必须检查一个基本情况,所以只有当你的 ['function:and', ['variable:X', 'function:>=', 'value:13'], ['function:==', ['variable:R', 'function:>=', 'value:1'], ['variable:Z', 'function:==', 'variable:K'] ] ] 键的值包含未经处理的值时才进行递归:

args

然后你会得到这个:

def walk(self, args):
    left = self.to_dict(args[0])
    right = self.to_dict(args[1])
    if isinstance(left, dict):
        if 'args' in left.keys() and isinstance(left['args'][0], list):
            left = self.walk(left['args'])
    if isinstance(right, dict):
        if 'args' in right.keys() and isinstance(right['args'][0], list):
            right = self.walk(right['args'])
    args = [left, right]
    return args

如果您的输入列表是一个常规结构,并且在函数名字段后面始终包含参数字段,那么也会更容易。然后,您可以大大简化{ 'args': [ { 'args': [{ 'variable': 'X'}, { 'value': '13'}], 'function': '>='}, { 'args': [ { 'args': [ { 'variable': 'R'}, { 'value': '1'}], 'function': '>='}, { 'args': [ { 'variable': 'Z'}, { 'variable': 'K'}], 'function': '=='}], 'function': '=='}], 'function': 'and'} 方法。