zoukankan      html  css  js  c++  java
  • 第一部分:数据结构和算法

    1.6、实现字典中的键映射多个值

    一般对于字典来说,键和值都是一一对应的,如果需要实现实现一个键对应多个值,那么就需要借助列表或者其他的数据结构实现,但是问题也来了,列表在插入数据的时候,需要事先进行判断,这样就会产生额外的工作,如何避免在判断值得数据类型的前提下,实现一对多呢?

    from collections import defaultdict
    d = defaultdict(list)      #设置字典的value的数据类型默认为list
    d['a'].append(1)
    d['a'].append(2)
    d['b'].append(4)
    
    d = defaultdict(set)       #设置字典的value的数据类型默认为set
    d['a'].add(1)
    d['a'].add(2)
    d['b'].add(4)

    1.7、实现字典排序

    默认字典是无序的,但是如果想要创建一个字典,在迭代或者序列化的时候可以保持元素插入的顺序,如何实现?

    from collections import OrderedDict
    def ordered_dict():
        d = OrderedDict()
        d['foo'] = 1
        d['bar'] = 2
        d['spam'] = 3
        d['grok'] = 4
    # Outputs "foo 1", "bar 2", "spam 3", "grok 4"
        for key in d:
            print(key, d[key])
    
    ordered_dict()

    比如如果需要编码为json的时候,精确控制编码之后的顺序,可以使用OrderedDict来创建这样一个字典;

    注意:OrderedDict内部维护着一个插入顺序的双向链表,所以OrderedDict是普通字典的两倍,如果需要将大量的数据读入的这种字典中的时候,需要仔细衡量;

    1.8、字典的运算

    如何实现在字典中执行一些运算操作

    下面是股票名和对应的价格

    prices = {
    'ACME': 45.23,
    'AAPL': 612.78,
    'IBM': 205.55,
    'HPQ': 37.20,
    'FB': 10.75
    }
    
    min_price = min(zip(prices.values(), prices.keys()))      #zip将两个列表的元素一一对应,为元祖
    print(min_price)
    max_price = max(zip(prices.values(), prices.keys()))
    print(max_price)


    #可以利用min和max函数中提供的key,获取最大值或者最小值对应的键的信息
    print(min(prices, key=lambda k: prices[k]))
    print(max(prices, key=lambda k: prices[k]))
     

    注意:在上述中使用到了(值,键)对,但是,如果多个元素存在相同值的时候,键会决定返回的结果,如下:

    prices = { 'AAA' : 45.23, 'ZZZ': 45.23 }
    print(min(zip(prices.values(), prices.keys())))
    print(max(zip(prices.values(), prices.keys())))

    1.9、查找两个字典的相同点

    字典就是一个键与值的映射关系表,keys()返回一个键的集合列表,其支持集合操作(并,交,差运算),但是values()因为值的元素可能存在重复,所以不支持集合操作,可以将values()转换为set,然后再进行集合操作;

    items()返回的是元祖对象,支持集合操作;如下

    a = {
    'x' : 1,
    'y' : 2,
    'z' : 3
    }
    b = {
    'w' : 10,
    'x' : 11,
    'y' : 2
    }
    
    print(a.keys() & b.keys())
    
    print(a.keys() - b.keys())
    
    print(a.items() & b.items())
    
    c = {key:a[key] for key in a.keys() - {'z','w'}}
    print(c)
    
    结果如下:
    
    {'x', 'y'}
    {'z'}
    {('y', 2)}
    {'x': 1, 'y': 2}

    1.10 删除序列相同元素并保持顺序

    def dedupe(items):
        seen = set()
        for item in items:
            if item not in seen:
                yield item
                seen.add(item)
    
    a = [1, 5, 2, 1, 9, 1, 5, 10]
    c = list(dedupe(a))         #生成器可以被循环打印元素,也可以被直接转换为list
    print(dedupe(c))
    print(c)
    
    
    结果如下:
    <generator object dedupe at 0x00000000030331B0>
    [1, 5, 2, 9, 10]
    1
    5
    2
    9
    10

    如果上述序列都是hashabled的,那么可以直接通过set()或者生成器解决,但是如果序列不是hashabled的,那么就需要将序列转化为hashabled的,如下:

    def dedupe(items, key=None):
        seen = set()                     #此处的集合只用于中间判断元素是否有重合,使用yield可以让函数每次执行的时候,记得之前seen集合的元素
        for item in items:
            val = item if key is None else key(item)
            if val not in seen:
                yield item
                seen.add(val)
    
    a = [ {'x':1, 'y':2}, {'x':1, 'y':3}, {'x':1, 'y':2}, {'x':2, 'y':4}]
    print(list(dedupe(a, key=lambda d: (d['x'],d['y']))))     #key用于将字典中的值转化为元祖

    print(list(dedupe(a, key=lambda d: d['x'])))

    对于一个序列,如果想要消除重复的元素,可以直接通过set(),就可以实现,但是这样会打乱元素的顺序,所以通常使用生产器的方式更为普遍;使用生成器的方式不仅在序列处理的时候可以使用,在文件处理的时候照样可以去掉重复的行;

    上述的函数的key模仿了min、max、sorted等函数;

    1.11、切片命名

    items = [0, 1, 2, 3, 4, 5, 6]
    a = slice(2, 4)      #使用内置函数创建切片对象,是的代码更为可读
    print(items[a])
    items[a] = [10,11]
    print(items)
    
    del items[a]
    print(items)

    1.12、找到序列中出现最多的元素

    Counter在几乎所有制表或者计算的场合非常有用

    words = [
    'look', 'into', 'my', 'eyes', 'look', 'into', 'my', 'eyes',
    'the', 'eyes', 'the', 'eyes', 'the', 'eyes', 'not', 'around', 'the',
    'eyes', "don't", 'look', 'around', 'the', 'eyes', 'look', 'into',
    'my', 'eyes', "you're", 'under'
    ]
    from collections import Counter
    word_counts = Counter(words)
    
    top_three = word_counts.most_common(3)      #找到频度出现最多的三个单词
    print(top_three)
    
    print(word_counts['not'])     #单词not的个数

    Counter可以非常容易的进行数学运算

    morewords = ['why','are','you','not','looking','in','my','eyes']
    a = Counter(words)
    b = Counter(morewords)
    
    c = a + b
    print(c)
    
    d = a - b
    print(d)
    
    结果为:
    
    Counter({'eyes': 9, 'the': 5, 'look': 4, 'my': 4, 'into': 3, 'around': 2, 'not': 2, 'looking': 1, "you're": 1, 'under': 1, "don't": 1, 'are': 1, 'you': 1, 'why': 1, 'in': 1})
    Counter({'eyes': 7, 'the': 5, 'look': 4, 'into': 3, 'around': 2, 'my': 2, 'under': 1, "you're": 1, "don't": 1})

    1.13 、通过某个关键字排序某个字典

    通过使用 operator 模块的 itemgetter 函数,可以非常容易的排序这样的数据结构;

    rows = [
    {'fname': 'Brian', 'lname': 'Jones', 'uid': 1003},
    {'fname': 'David', 'lname': 'Beazley', 'uid': 1002},
    {'fname': 'John', 'lname': 'Cleese', 'uid': 1001},
    {'fname': 'Big', 'lname': 'Jones', 'uid': 1004}
    ]
    
    
    from operator import itemgetter
    rows_by_fname = sorted(rows, key=itemgetter('fname'))
    rows_by_uid = sorted(rows, key=itemgetter('uid'))
    print(rows_by_fname)
    print(rows_by_uid)
    
    rows_by_lfname = sorted(rows, key=itemgetter('lname','fname'))     #也支持多个key
    print(rows_by_lfname)

    当然,上述itemgetter函数也可以使用lamdba代替

    rows_by_fname = sorted(rows, key=lambda r: r['fname'])
    rows_by_lfname = sorted(rows, key=lambda r: (r['lname'],r['fname']))

    最后,itemgetter函数同样也适用于min和max函数;

    rows = [
    {'fname': 'Brian', 'lname': 'Jones', 'uid': 1003},
    {'fname': 'David', 'lname': 'Beazley', 'uid': 1002},
    {'fname': 'John', 'lname': 'Cleese', 'uid': 1001},
    {'fname': 'Big', 'lname': 'Jones', 'uid': 1004}
    ]


    from operator import itemgetter
    rows_by_fname = sorted(rows, key=itemgetter('fname'))
    rows_by_uid = sorted(rows, key=itemgetter('uid'))
    print(rows_by_fname)
    print(rows_by_uid)

    rows_by_lfname = sorted(rows, key=itemgetter('lname','fname'))
    print(rows_by_lfname)



    1.14、排序不支持原生比较的对象
    class User:
        def __init__(self, user_id):
            self.user_id = user_id
        def __repr__(self):
            return 'User({})'.format(self.user_id)
    def sort_notcompare():
        users = [User(23), User(3), User(99)]
        print(users)
        print(sorted(users, key=lambda u: u.user_id))
    
    sort_notcompare()

    或者使用attrgetter实现

    users = [User(23), User(3), User(99)]
    from operator import attrgetter
    print(sorted(users,key=attrgetter('user_id')))

    1.15、通过某个字段将记录分组

     

    
    
    rows = [
    {'address': '5412 N CLARK', 'date': '07/01/2012'},
    {'address': '5148 N CLARK', 'date': '07/04/2012'},
    {'address': '5800 E 58TH', 'date': '07/02/2012'},
    {'address': '2122 N CLARK', 'date': '07/03/2012'},
    {'address': '5645 N RAVENSWOOD', 'date': '07/02/2012'},
    {'address': '1060 W ADDISON', 'date': '07/02/2012'},
    {'address': '4801 N BROADWAY', 'date': '07/01/2012'},
    {'address': '1039 W GRANVILLE', 'date': '07/04/2012'},
    ]

    from
    operator import itemgetter from itertools import groupby # Sort by the desired field first rows.sort(key=itemgetter('date')) # Iterate in groups for date, items in groupby(rows, key=itemgetter('date')): print(date) for i in items: print(' ', i)

    1.16、过滤序列元素

     最常用的方式是使用列表推导的方式;但是使用列表推导的方式有可能会占用大量的内存,如果对内存数据比较敏感,可以使用生成器替代;

    mylist = [1, 4, -5, 10, -7, 2, 3, -1]
    a = [n for n in mylist if n > 0]
    print(a)
    b= [n for n in mylist if n < 0]
    print(b)

    生成器方法如下:

    pos = (n for n in mylist if n > 0)     #将列表变为元祖,就会变为生成器
    print(pos)
    
    for n in pos:
        print(n)

    还可以采用filter函数实现序列元素的过滤;

    values = ['1', '2', '-3', '-', '4', 'N/A', '5']
    def is_int(val):
        try:
            int(val)
            return True
        except ValueError:
            return False
    ivals = list(filter(is_int, values))
    print(ivals)

    过滤条件对于序列进行过滤,对于不符合条件的元素使用固定元素替换

    clip_neg = [n if n > 0 else 0 for n in mylist]
    print(clip_neg)

    另外一个过滤工具是,可以根据一个序列的元素去过滤另外一个序列的元素;

    addresses = [
    '5412 N CLARK',
    '5148 N CLARK',
    '5800 E 58TH',
    '2122 N CLARK'
    '5645 N RAVENSWOOD',
    '1060 W ADDISON',
    '4801 N BROADWAY',
    '1039 W GRANVILLE',
    ]
    counts = [ 0, 3, 10, 4, 1, 7, 6, 1]
    
    
    from itertools import compress
    more5 = [n > 5 for n in counts]    #返回布尔类型
    print(more5)
    print(list(compress(addresses,more5)))     #compress函数返回的是一个迭代器,如果希望以列表的方式查看,就转换为列表的形式;

    1.17、在字典中提取子集

    最简单的方式就是使用字典推导

    prices = {
    'ACME': 45.23,
    'AAPL': 612.78,
    'IBM': 205.55,
    'HPQ': 37.20,
    'FB': 10.75
    }
    
    p1 = {key: value for key, value in prices.items() if value > 200}
    print(p1)
    
    tech_names = {'AAPL', 'IBM', 'HPQ', 'MSFT'}
    p2 = {key: value for key, value in prices.items() if key in tech_names}
    print(p2)

    1.18、映射名称到序列元素

    collections.namedtuple()

    1.19、转换并同时计算

    对于min()、max()、sum()等函数,需要先对元素进行过滤,然后再进行计算;

    通过生成器表达式进行计算;

    nums = [1, 2, 3, 4, 5]
    s = sum(x * x for x in nums)
    print(s)
    
    import os
    files=os.listdir('/')
    print(files)       #files返回列表,元素为目录下面的文件名/目录名
    if any(name.endswith('.py') for name in files):
        print('there have python file' )
    
    s = ('ACME', 50, 123.45)
    print(','.join(str(x) for x in s))


    portfolio = [
    {'name':'GOOG', 'shares': 50},
    {'name':'YHOO', 'shares': 75},
    {'name':'AOL', 'shares': 20},
    {'name':'SCOX', 'shares': 65}
    ]
    min_shares = min(s['shares'] for s in portfolio)
    print(min_shares)


    min_shares = min(portfolio, key=lambda s: s['shares'])
    print(min_shares)

    也可以不使用生成器表达式计算

    nums = [1, 2, 3, 4, 5]
    s = sum([x * x for x in nums])            #不使用生成器表达式的方式,会先创建一个列表

    1.20、合并多个字典或者映射

    需求:需要将多个字典或者映射逻辑上合并为一个之后,再执行一些其他的操作;

    from collections import ChainMap
    a = {'x': 1, 'z': 3 }
    b = {'y': 2, 'z': 4 }
    d = {'a':1,'b':6}
    
    c = ChainMap(a,b,d)
    print(c)
    print(c['y'])
    print(c['z'])
    ChainMap默认上不会改变原来的序列或者字典,这个字典不是真正意义上的字典;这和update不同;合并之后的字典支持大部分的字典操作;
    需要注意的是:对于合并ChainMap生成的合并字典,删除和更新操作,只会影响第一个原来的字典;ChianMap使用原来的字典,但是自己不会新创建字典;





  • 相关阅读:
    EntityFramework 数据库的迁移
    free之后将指针置为NULL
    结构体对齐及#pragma详细解释
    大端小端
    TCP封包解包---如有错误,请纠正!
    堆栈----好久没有更新了
    附近点搜索
    LRU Cache
    电商的秒杀和抢购
    搜索关键词智能提示suggestion
  • 原文地址:https://www.cnblogs.com/cqq-20151202/p/5985985.html
Copyright © 2011-2022 走看看