【问题标题】:Nested for-loops and dictionaries in finding value occurrence in string在字符串中查找值出现的嵌套 for 循环和字典
【发布时间】:2015-09-22 21:24:49
【问题描述】:

我的任务是创建一个字典,其键是在字符串中找到的元素,其值计算每个值的出现次数。

例如。

"abracadabra" → {'r': 2, 'd': 1, 'c': 1, 'b': 2, 'a': 5}

我这里有 for 循环逻辑:

xs = "hshhsf"
xsUnique = "".join(set(xs))

occurrences = []
freq = []

counter = 0

for i in range(len(xsUnique)):
    for x in range(len(xs)):
        if xsUnique[i] == xs[x]:
            occurrences.append(xs[x])
            counter += 1
    freq.append(counter)
    freq.append(xsUnique[i])
counter = 0 

这正是我想要它做的,除了使用列表而不是字典。我怎样才能使counter 成为一个值,而xsUnique[i] 成为新字典中的一个键?

【问题讨论】:

    标签: python dictionary


    【解决方案1】:

    最简单的方法是使用计数器:

    >>> from collections import Counter
    >>> Counter("abracadabra")
    Counter({'a': 5, 'r': 2, 'b': 2, 'c': 1, 'd': 1})
    

    如果不能使用 Python 库,可以使用dict.get,默认值为0 来制作自己的计数器:

    s="abracadabra"
    count={}
    for c in s:
        count[c] = count.get(c, 0)+1
    
    >>> count
    {'a': 5, 'r': 2, 'b': 2, 'c': 1, 'd': 1}    
    

    或者,您可以使用dict.fromkeys() 将计数器中的所有值设置为零,然后使用它:

    >>> counter={}.fromkeys(s, 0)
    >>> counter
    {'a': 0, 'r': 0, 'b': 0, 'c': 0, 'd': 0}
    >>> for c in s:
    ...    counter[c]+=1
    ... 
    >>> counter
    {'a': 5, 'r': 2, 'b': 2, 'c': 1, 'd': 1}
    

    如果你真的想要最少的 Pythonic,即你可能在 C 中做的事情,你可能会做:

    1. 为设置为0的所有可能的ascii值创建一个列表
    2. 遍历字符串并计算出现的字符数
    3. 打印非零值

    例子:

    ascii_counts=[0]*255
    s="abracadabra"
    
    for c in s:
        ascii_counts[ord(c)]+=1
    
    for i, e in enumerate(ascii_counts):
        if e:
            print chr(i), e 
    

    打印:

    a 5
    b 2
    c 1
    d 1
    r 2
    

    但是,这不适用于 Unicode,因为您需要 more than 1 million 列表条目...

    【讨论】:

    • 完美,这正是我想要的!我不能为此使用任何 Python 库。
    【解决方案2】:

    您可以使用zip 函数将您的列表转换为字典:

    >>> dict(zip(freq[1::2],freq[0::2]))
    {'h': 3, 's': 2, 'f': 1}
    

    但作为更pythonic和相当优化的方式,我建议使用collections.Counter

    >>> from collections import Counter
    >>> Counter("hshhsf")
    Counter({'h': 3, 's': 2, 'f': 1})
    

    正如你所说,你不想导入任何模块,你可以使用字典,使用dict.setdefault 方法和一个简单的循环:

    >>> d={}
    >>> for i in xs:
    ...    d[i]=d.setdefault(i,0)+1
    ... 
    >>> d
    {'h': 3, 's': 2, 'f': 1}
    

    【讨论】:

    • 我想我会寻找最少的pythonic方式来做到这一点,因为我本质上是在学习如何制作一个 Counter 函数。我是这种东西的新手,所以我还没有发挥它的潜力。
    • @ChrisAngj 如果你想用这个问题来练习和学习它是可以的,但是正确的方法是使用collections.Counter。也可以直接用字典来得到期望的结果!
    【解决方案3】:

    我猜有一个learning 原因来解释你为什么使用两个forloops? 无论如何,这里有一些不同的解决方案:

    # Method 1
    xs = 'hshhsf'
    xsUnique = ''.join(set(xs))
    
    freq1 = {}
    for i in range(len(xsUnique)):
        for x in range(len(xs)):
            if xsUnique[i] == xs[x]:
                if xs[x] in freq1:
                    freq1[xs[x]] += 1
                else:
                    freq1[xs[x]] = 1 # Introduce a new key, value pair
    
    # Method 2
    # Or use a defaultdict that auto initialize new values in a dictionary
    # https://docs.python.org/2/library/collections.html#collections.defaultdict
    
    from collections import defaultdict
    
    freq2 = defaultdict(int) # new values initialize to 0
    for i in range(len(xsUnique)):
        for x in range(len(xs)):
            if xsUnique[i] == xs[x]:
                # no need to check if xs[x] is in the dict because 
                # defaultdict(int) will set any new key to zero, then
                # preforms it's operation.
                freq2[xs[x]] += 1
    
    
    # I don't understand why your using 2 forloops though
    
    # Method 3
    string = 'hshhsf' # the variable name `xs` confuses me, sorry
    
    freq3 = defaultdict(int)
    for char in string:
        freq3[char] += 1
    
    # Method 4
    freq4 = {}
    for char in string:
        if char in freq4:
            freq4[char] += 1
        else:
            freq4[char] = 1
    
    
    
    print 'freq1: %r\n' % freq1
    print 'freq2: %r\n' % freq2
    print 'freq3: %r\n' % freq3
    print 'freq4: %r\n' % freq4
    
    print '\nDo all the dictionaries equal each other as they stand?'
    print 'Answer: %r\n\n'  % (freq1 == freq2 and freq1 == freq3 and freq1 == freq4)
    
    # convert the defaultdict's to a dict for consistency
    freq2 = dict(freq2)
    freq3 = dict(freq3)
    
    print 'freq1: %r' % freq2
    print 'freq2: %r' % freq2
    print 'freq3: %r' % freq3
    print 'freq4: %r' % freq4
    

    输出

    freq1: {'h': 3, 's': 2, 'f': 1}
    freq2: defaultdict(<type 'int'>, {'h': 3, 's': 2, 'f': 1})
    freq3: defaultdict(<type 'int'>, {'h': 3, 's': 2, 'f': 1})
    freq4: {'h': 3, 's': 2, 'f': 1}
    
    Do all the dictionaries equal each other as they stand?
    Answer: True
    
    
    freq1: {'h': 3, 's': 2, 'f': 1}
    freq2: {'h': 3, 's': 2, 'f': 1}
    freq3: {'h': 3, 's': 2, 'f': 1}
    freq4: {'h': 3, 's': 2, 'f': 1}
    [Finished in 0.1s]
    

    或者像 dawg 所说,使用集合标准库中的 Counter

    柜台文件

    https://docs.python.org/2/library/collections.html#collections.Counter

    默认字典文档

    https://docs.python.org/2/library/collections.html#collections.defaultdict

    收藏库文档

    https://docs.python.org/2/library/collections.html

    【讨论】:

    • 我使用了两个 for 循环,因为这是我自学的方式。学习一种更短、更高效的方法总是很酷的。谢谢!
    • 这就解释了。有许多简单的方法可以解决 Python 中有关结构化数据的问题。查看列表和字典理解
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-09-13
    • 1970-01-01
    • 1970-01-01
    • 2020-04-08
    • 2019-07-16
    • 2014-01-29
    • 2017-12-25
    相关资源
    最近更新 更多