简体   繁体   English

是否有更简洁/ pythonic的方式来做到这一点? (计算头部最长的seq,硬币翻转的尾巴)

[英]Is there a more succinct / pythonic way to do this? (counting longest seq of heads, tails in coin flips)

Count the longest sequence of heads and tails in 200 coin flips. 计算200个硬币翻转中最长的头部和尾部序列。
I did this - is there a niftier way to do it in python? 我这样做了 - 在python中有没有更快的方法呢? (without being too obfuscated) (没有太混淆)

import random

def toss(n):
    count = [0,0]
    longest = [0,0]
    for i in xrange(n):
        coinface = random.randrange(2)
        count[coinface] += 1
        count[not coinface] = 0

        if count[coinface] > longest[coinface]:
            longest[coinface] = count[coinface]      
        #print coinface, count, longest  

    print "longest sequence heads %d, tails %d" %tuple(longest)

if __name__ == '__main__':
    toss(200)

see this for what prompted my playing 看到这是为了促使我的演奏

def coins(num):
    lst = [random.randrange(2) for i in range(num)]
    lst = [(i, len(list(j))) for i, j in itertools.groupby(lst)]
    tails = max(j for i, j in lst if i)
    heads = max(j for i, j in lst if not i)
    return {1: tails, 0: heads}
import collections, itertools, random

def makesequence(choices=2, length=200):
  return [random.randrange(choices) for _ in itertools.repeat(None, length)]

def runlengths(sequence):
  runlength_by_item = collections.defaultdict(set)
  for key, group in itertools.groupby(sequence):
    runlength_by_item[key].add(sum(1 for _ in group))
  return dict((k, max(v)) for k, v in runlength_by_item.items())

As you'll notice, this is much more "decoupled" -- runlengths is a completely general way to determine the maximal run-lengths of different hashable items in any iterable (highly reusable if you need such run-lengths in a variety of different contexts), just as makesequence is a completely general way to make a list of random numbers given list length and number of choices for each random number. 正如您将注意到的,这更加“解耦” - runlengths是一种完全通用的方法来确定任何可迭代中不同可清洗项目的最大运行长度(如果您需要各种不同的运行长度,则可高度重复使用)上下文),正如makesequence是一个完全通用的方法来给出列表长度和每个随机数的选择数量的随机数列表。 Putting these two together may not offer an optimal point-solution to a given, highly specific problem, but it will come close, and building up your little library of reusable "building blocks" will have much higher longer-term returns than just solving each specific problem by entirely dedicated code. 将这两者放在一起可能无法为给定的,高度具体的问题提供最佳的点解决方案,但它会接近,并且构建可重复使用的“构建块”的小库将比仅解决每个问题具有更高的长期回报。完全专用的代码的具体问题。

You can use itertools , which is a much more Pythonic way to do this: 您可以使用itertools ,这是一种更加Pythonic的方式来执行此操作:

def toss(n):
    rolls = [random.randrange(2) for i in xrange(n)]
    maximums = [0, 0]
    for which, grp in itertools.groupby(rolls):
        maximums[which] = max(len(list(grp)), maximums[which])

    print "Longest sequence of heads %d, tails %d" % tuple(maximums)

Another inefficient solution :-) 另一个低效的解决方案:-)

import random, re
s = ''.join(str(random.randrange(2)) for c in range(10))
print s
print max(re.findall(r'0+', s))
print max(re.findall(r'1+', s))

>>> 
0011100100
00
111
>>> 
>>> def toss(count):
        result = []
        for i in range(count):
            result.append("HT"[random.randrange(0, 2)])
        return ''.join(result)

>>> s = toss(200)
>>> h_max = max(len(x) for x in s.split("T"))
>>> t_max = max(len(x) for x in s.split("H"))
>>> print h_max, t_max
4 6

This isn't really pythonic so much as tortured, but here's a short version (with meaningless 1-character variable names, no less!) 这不是真正的pythonic如此折磨,但这是一个简短的版本(无意义的1个字符的变量名称,不能少!)

import random
x = ''.join([chr(random.randrange(2)) for i in range(200)])
print max([len(s) for s in x.split(chr(0)) + x.split(chr(1))])

It is probably an axiom that any code can be made more succinct. 任何代码都可以更简洁,这可能是一个公理。 Yours looks perfectly pythonic, though. 然而,你的看起来完全是pythonic。

Actually, on reflection perhaps there is no succinctness axiom like that. 实际上,在反思中,也许没有那种简洁的公理。 If succinct means "marked by compact precise expression without wasted words," and if by "words" we mean words of code and not of memory, then a single word program cannot be made more succinct (unless, perhaps, it is the "exit" program). 如果简洁意味着“标记紧凑精确表达而没有浪费的话”,如果用“单词”表示代码而不是记忆,那么单个单词程序就不能简洁(除非它可能是“退出” “节目)。

If pythonic means "of extraordinary size and power", then it seems antagonistic to succinctness unless we restrict our definition to power only. 如果pythonic意味着“具有非凡的大小和力量”,那么除非我们将我们的定义仅限于权力,否则它对于简洁似乎是对立的。 I'm not convinced your program resembles a prophetic oracle at all, although you might implement it as an ascii portrait of a particular prophetic oracle. 我不相信你的程序完全类似于预言的神谕,尽管你可能会把它作为特定预言神谕的ascii肖像来实现。 It doesn't look like a snake, so there's room for improvement there too. 它看起来不像蛇,所以那里也有改进的余地。

import random

def toss(n):
    '''
     ___     ____________
<<<((__O\   (__<>___<>__ \   ____
       \ \_(__<>___<>__)\O\_/O___>-<  hiss
        \O__<>___<>___<>)\___/

    '''
    count = [0,0]
    longest = [0,0]
    for i in xrange(n):
        coinface = random.randrange(2)
        count[coinface] += 1
        count[not coinface] = 0

        if count[coinface] > longest[coinface]:
            longest[coinface] = count[coinface]
        #print coinface, count, longest

    print "longest sequence heads %d, tails %d" %tuple(longest)

if __name__ == '__main__':
    toss(200)

Nifty, huh? 好漂亮,对吧?

import random, itertools

def toss(n):
    faces = (random.randrange(2) for i in range(n))
    longest = [0, 0]
    for face, seq in itertools.groupby(faces):
        longest[face] = max(longest[face], len(list(seq)))
    print "longest sequence heads %d, tails %d" % tuple(longest)

String scanning algorithm 字符串扫描算法

If you are looking for a fast algorithm, then you can use the algorithm I developed recently for an interview question that asked for the longest string of consecutive letters in a string. 如果您正在寻找快速算法,那么您可以使用我最近开发的算法来获取面试问题,该问题要求字符串中最长的连续字母串。 See blog entry here . 请参阅此处的博客条目

def search_longest_substring(s):
    """
    >>> search_longest_substring('AABBBBCBBBBACCDDDDDDAAABBBBCBBBBACCDDDDDDDAAABBBBCBBBBACCDDDDDDA')
    (7, 'D')
    """
    def find_left(s, midc, mid, left):
        for j in range(mid-1, left-1, -1):
            if s[j] != midc:
                return j + 1
        return left
    def find_right(s, midc, mid, right):
        for k in range(mid+1, right):
            if s[k] != midc:
                return k
        return right
    i, longest = 0, (0, '')
    while i < len(s):
        c = s[i]
        j = find_left(s, c, i, i-longest[0])
        k = find_right(s, c, i, len(s))
        if k-j > longest[0]:
            longest = (k-j, c)
        i = k + longest[0]
    return longest

if __name__ == '__main__':
    import random
    heads_or_tails = "".join(["HT"[random.randrange(0, 2)] for _ in range(20)])
    print search_longest_substring(heads_or_tails)
    print heads_or_tails

This algorithm is O(n) in worst case (all coin flips are identical) or O(n/m) in average case (where m is the length of the longest match). 该算法在最坏的情况下是O(n)(所有硬币翻转是相同的)或平均情况下的O(n / m)(其中m是最长匹配的长度)。 Feel free to correct me on this. 请随意纠正我。

The code is not especially pythonic (ie it does not use list comprehensions or itertools or other stuff). 代码不是特别pythonic(即它不使用列表itertoolsitertools或其他东西)。 It's in python and it's a good algorithm. 它是在python中,它是一个很好的算法。

Micro-optimizations 微优化

For the micro-optimization crowd, here are changes that make this really scream in python 2.6 on a Windows Vista laptop: 对于微优化人群,以下是在Windows Vista笔记本电脑上使python 2.6真正尖叫的变化:

def find_left(s, midc, mid, left):
    j = mid - 1
    while j >= 0:
        if s[j] != midc:
            return j + 1
        j -=  1
    return left
def find_right(s, midc, mid, right):
    k = mid+1
    while k < right:
        if s[k] != midc:
            return k
        k += 1
    return right

Timing results for 1000 iterations with timeit : 使用timeit进行1000次迭代的计时结果:

range: 2.670
xrange: 0.3268
while-loop: 0.255

Adding psyco import to the file: psyco导入添加到文件中:

try:
    import psyco
    psyco.full()
except ImportError:
    pass

0.011 on 1000 iterations with psyco and while-loop. 使用psyco和while循环进行1000次迭代0.011。 So with judicious micros-optimizations and importing psyco , the code runs 250-ish times faster. 因此,通过明智的微优化和导入psyco ,代码运行速度提高了250倍。

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

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