[Python程序设计] 2020年10月9日 问题C: 电商一

这学期选了Python的选修,任课的是竞赛队的老师。本来以为用了很久Python了,这课听起来会有点无聊,结果老师讲了很多以前不知道的trick,还挺有意思,像f-string,for-else之类的。感觉这个课适合已经学过的人去查漏补缺,对于新手入门来说还是跨度太大了。

作业一直布置在校内OJ,以前的题感觉都没啥好写的,今天有个题感觉可以复习下Python下的排序,来写写。

1. 题目简述

  • 完整的题目我会放在最后面。
  • 输入一个整数n表述书籍总数,后面是n组数据,每组一行,组内用空格分隔,共有7列,分别是
    • 书名
    • 销量
    • 出版年
    • 出版月
    • 出版日
    • 价格
    • 用户评分
  • 要求对书籍进行排序。给定数据保证没有排名一样的书籍。排序优先级从高到低是
    • 价格,越低越好
    • 出版时间(年月日合体),越新越好
    • 销量,越高越好
    • 用户评分,越高越好
  • 然后输出这n本书籍的信息,格式和输入给定的一样,只是记录之间的顺序变了。

2. 解与解释

  • 先放代码

  •   def main():
          lz = list()
          n = int(input())
          for i in range(n):
              argLz = input().split()
              argLz[1:] = map(int,argLz[1:])
              lz.append(argLz)
          lz.sort(key = lambda x: [-x[5],x[2],x[3],x[4],x[1],x[6]],reverse=True)
          for item in lz:
              print(' '.join(map(str,item)))
      
      main()
    
  • 能AC,效率还不错。

  • 这里用的是列表嵌套列表来存储的,在sorted前,lz里面的内容看起来是这样的

    •   [['CPrimerPlus', 3000, 2013, 12, 6, 60, 44],
         ['ComputerSystemsAProgrammersPerspective', 8000, 2015, 3, 12, 156, 39],
         ['TheCProguammingLanguage', 50000, 1978, 2, 22, 5, 46]]
      
  • argLz[1:] = map(int,argLz[1:])利用了列表切片返回引用的特性,对列表进行了复写。这个语句的意思是,对argLz列表从第一到最后一个元素,每个元素都转换为整数,返回一个新列表,然后将其从argLz的第一个元素开始复写。

  • lz = sorted(lz,key = lambda x: [-x[5],x[2],x[3],x[4],x[1],x[6]],reverse=True)利用了sorted函数的自定义排序,还有列表的比较功能。

    • key代表指定一个比较的标准,用什么来比较。其使用一个函数来描述,每次接收列表里的一个元素,返回一个比较量(任何类型,只要能和其他元素产生的比较量进行比较就行)。
    • 这里使用了一个匿名函数lambda来实现,因为这个比较量的产生函数只在这里使用一次,之后用不到,没有必要单独拎出来。
    • 如果不指定key(默认key=None),将会用列表里的元素本身来比较。
    • 这里给每个记录指定了一个比较量[-x[5],x[2],x[3],x[4],x[1],x[6]],之后sorted函数内部在排序时,将会按这个列表进行排序。
    • [-x[5],x[2],x[3],x[4],x[1],x[6]] 的中 x[i] 指示的分别是价格、出版年、出版月、出版日、销量、用户评分。按照列表的比较规则,将会从索引0开始向后比较,然后比较索引1,2,3。直到能比出结果为止。因为唯独价格是越低越好,所以给价格前面加个负号。价格越低,负价格越高,这样就跟后面一致了。
  • print(' '.join(map(str,item)))利用了str.join(list)方法,其表示用str为间隔,拼接list内的每个字符串。由于记录中有一些是整数,所以利用map将每个元素都转换为字符串(字符串转换为字符串不会变化)。

3. 扩展

3.1 列表切片的丰富用途

  • 列表是Python非常精彩的一个数据结构,使用简洁,功能强大,效率……要啥自行车。

  • 利用切片几乎可以完成维护列表的所有步骤。

  • 插入元素

    •   l = list() # l是一个空列表
        l[0:] = [1,2,3]
        l
        # [1, 2, 3]
      
    • 表示从索引0(含)开始向后插入。

    • 如果给出的区间左超出了列表的索引范围,将会插入到最后一个元素后面。

  • 覆盖元素

    •   l = [1,2,3,4,5]
        l[2:4] = [-9,-8,-7,-6,-5,-4,-3]
        l
        # [1, 2, -9, -8, -7, -6, -5, -4, -3, 5]
      
    • 表示将索引2,3处的元素覆盖为-9,-8,-7,-6,-5,-4,-3

    • 注意区间左闭右开的特性。

  • 删除元素

    •   l = [1,2,3,4,5]
        l[1:3] = []
        l
        # [1, 4, 5]
      
    • 表示将索引1,2处的元素删除。

  • 逆序

    •   l= [1,2,3,4,5]
        l[::-1]
        #  [5, 4, 3, 2, 1]
      

3.2 为什么要多用map

  • 首先肯定是简单,能用map 就可以省去一个循环(写成list comprehension也是循环)。

    •   l = list(range(10))
        ll = list(map(lambda x:-x,l))
        ll
        #  [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
      
    • 等价的写法是

    •   ll = [-x for x in l]
      
    • 或者

    •   for num in l:
        	ll += [2]
            #或者 ll.append(2)
      
  • 其次,map体现了函数式编程的思想。我能用map,就说明了我要把一个操作应用到很多元素上,每个元素被操作是独立的,这样的好处就是,可以很方便地利用处理器的并行,同时从多个位置开始处理,大幅提高处理效率。

    •   from multiprocessing import Pool
        def minus(x:int)->int:
        	return -x
        def main():
        	p = Pool(6) # 开启6个并行单元
        	l = list(range(10000))
        	ll = p.map(minus,l)
        main()
      
    • LinuxPython中可以正确运行,在Windows下需要手动序列化。

3.3 为什么要写def main

  • 从其他语言继承过来的习惯。
  • 因为不是写模块化的程序,写if __name__ == "__main__":比较麻烦。
  • main函数里写的变量和语句都是局部的,不会污染全局区。

3.4 sortsorted

  • sortsortedPython23之间有一些变化,这里只说3的。
  • sortsorted的区别在于,sortlist的一个方法,调用后对list本身排序。sorted是一个公共函数,可以接收所有可迭代的对象,返回一个排过序的列表,但不对被排序的对象做修改。
  • 但是sortsorted的参数都是一样的。
    • key: 指定排序依据。默认是None,用记录本身来做比较。如果指定了函数,该函数将会接收一个记录,返回一个比较量,之后排序中的比较都用比较量来比较,而不是记录本身。
    • reverse: 指定是否是递减序。默认是False,是递增序。
  • 不要自己写排序,除非有必要。一是效率,而是鲁棒性,肯定都不如现成的好。

4. 原题目

题目描述

大家都知道在电商网站上买东西时,网站会根据我们的搜索条件给出非常多的商品。这些商品会以依据某一种排序规则进行排序,依次呈现在我们面前。现在某电商网站关于书籍的排序依据有这么几项,综合、销量、出版时间、价格、用户评分。假设综合排名的规则为:首先看价格,价格低的排名靠前,如果价格相同,则看出版时间,出版的晚的排名靠前,如果这两项都相同则看销量,销量大的靠前,如果前三项均相同,最后看用户评分,用户评分高的排名靠前。

请依据此规则写一段给各个书按综合排名的程序。

输入

第一行为一个整数n(1

输出

n行,每行输出一本书的信息,与输入时格式一致(测试数据中保证没有排名一样的书籍,且所有整数均可以用int存储)。

样例输入

3
CPrimerPlus 3000 2013 12 6 60 44
ComputerSystemsAProgrammersPerspective 8000 2015 3 12 156 39
TheCProguammingLanguage 50000 1978 2 22 5 46

样例输出

TheCProguammingLanguage 50000 1978 2 22 5 46
CPrimerPlus 3000 2013 12 6 60 44
ComputerSystemsAProgrammersPerspective 8000 2015 3 12 156 39

你可能感兴趣的:(日常)