【问题标题】:How to sort tire sizes in python如何在python中对轮胎尺寸进行排序
【发布时间】:2012-12-27 07:11:17
【问题描述】:

我正在尝试从最小到最大对(字符串)轮胎尺寸列表进行排序。

['285/30/18',
 '285/30/19',
 '235/40/17',
 '315/25/19',
 '275/30/19']

应该排序为:

['235/40/17',
 '285/30/18',
 '315/25/19'
 '275/30/19',
 '285/30/19']

我基本上必须从右、中、左开始对字符串进行排序。

到目前为止我所拥有的(冒泡排序):

# this sorts the first numbers on the right.
nums = list(ulst)
for i in range(len(nums)):
     for j in range(i+1, len(nums)):
         if ulst[j].split('/')[2] < ulst[i].split('/')[2]:
             ulst[j], ulst[i] = ulst[i], ulst[j]

我现在要在不弄乱右行排序的情况下对中间进行排序,然后对左行进行排序....

如何在不创建 for/if 嵌套混乱的情况下解决此问题?

【问题讨论】:

    标签: python list sorting


    【解决方案1】:

    Python 有几个特性让这很容易做到。实际上,您可以在一个语句中完成所有操作:

    sorted(nums, key=lambda x: tuple(reversed(list(map(int, x.split("/"))))))
    

    x.split("/") 获取每个值并生成一个字符串列表:

    ["235", "40", "17"]
    

    使用map(int, ...) 给出整数列表:

    [235, 40, 17]
    

    reversed() 扭转局面:

    [17, 40, 235]
    

    tuple() 将其转换为元组:

    (17, 40, 235)
    

    与其他类似的元组相比,它给出了您想要的排序顺序。

    【讨论】:

    • 这强调了一个切线点:通常更喜欢像sorted 这样的内置行为,而不是实现自己的排序功能。当然,除非您的目标是实现排序功能。
    • reversed() 实际上返回一个迭代器。
    • @AshwiniChaudhary:谢谢,这提醒我检查它是否适用于 Python 3.x。我不得不在map()reversed() 之间添加一个额外的list()tuple() 很高兴接受迭代。
    • 这是正确的方法,但感觉有点间接。我认为像key=lambda x: list(map(int, x.split('/')))[::-1]) 或与tuple 相同的东西将与Py3 兼容,并且没有轻微的疣列表-> 元组转换或六个连续的) 字符..
    • 感谢您将其分解并以简洁的方式逐步解释!效果很好!
    【解决方案2】:

    一种方法是使用以下value 函数构造排序键,该函数以正确的顺序考虑三个字段:

    def value(s):
        arr = s.split('/')
        return arr[2] * 100000 + arr[1] * 1000 + arr[0]
    
    ulst = ['285/30/18', '285/30/19', '235/40/17', '315/25/19', '275/30/19']
    
    for i in range(len(ulst)):
         for j in range(i+1, len(ulst)):
             if value(ulst[j]) < value(ulst[i]):
                 ulst[j], ulst[i] = ulst[i], ulst[j]
    
    print ulst
    

    它的输出是,根据需要:

    ['235/40/17', '285/30/18', '315/25/19', '275/30/19', '285/30/19']
    

    如果您的轮胎尺寸是指定的 3/2/2 位数,这是一个相当安全的选择,这将正常工作 - 我从未见过低于 12 英寸的轮胎,而 100 英寸中的一个可能太大而无法骑行:-)

    【讨论】:

      【解决方案3】:

      使用str.splitreversedtuple的组合来创建与sorted一起使用的键函数:

      sizes = ['285/30/18',
               '285/30/19',
               '235/40/17',
               '315/25/19',
               '275/30/19']
      
      s = sorted(sizes, key=lambda z: tuple(reversed([int(i) for i in z.split("/")])))
      

      sorted 函数接受一个序列和一个键函数,并返回一个序列项的列表,该列表按键函数的返回值对列表中的每个项进行排序。这个关键函数lambda z首先将“/”字符上的项目拆分为一个字符串列表,然后将每个字符串转换为数字,然后将其传递给reversed函数,该函数给出反向迭代器传入序列的顺序(注意:尚未计算),tuple 函数计算反向迭代器,将其转换为可用于排序的序列。

      因此,格式为“a/b/c”的字符串序列将按 (c, b, a) 排序返回。这导致:

      >>> print s
      ['235/40/17', '285/30/18', '315/25/19', '275/30/19', '285/30/19']
      

      【讨论】:

      • 使用字符串比较而不是 int 比较是一个非常糟糕的主意:"19" &lt; "2" == True。不过,我对轮胎的了解非常有限,因此在这种特定情况下,所有合理的尺寸都可以。
      • 你是对的,当然。我已经对其进行了编辑以正确处理此问题。谢谢。
      【解决方案4】:

      很多很好的答案。如果您这样做只是为了例如缘故或快速的一次性解析或家庭作业,那么它们都说明字符串处理/排序很好。但是,如果您真的要围绕轮胎管理构建一个真正的应用程序,我会考虑为您的轮胎制作一个真实的轮胎模型:

      from ast import literal_eval
      from operator import attrgetter
      
      # Make a real object, because we can, and it's easy, and a real object is almost always better than abusing literal types
      class Tire(object):
          def __init__(self, width = 0, profile = 0, radius = 0): #now we have meaningful names to our indexed fields
              self.width = width
              self.profile = profile
              self.radius = radius
      
          # let's encapsulate the '{width}/{profile}/{radius}' string representation
          # as an attribute so we can access/set it like the "real" attributes
          @property
          def description(self):
              return '{}/{}/{}'.format(self.width, self.profile, self.radius)
      
          @description.setter
          def description(self, string):
              self.width, self.profile, self.radius = map(literal_eval, string.split('/')) #ast.literal_eval() is safer than just eval()
      
          # let's make a class side instance creation method that can instantiate and set the description directly too
          @classmethod
          def fromDescription(me, descriptionString):
              newTire = me()
              newTire.description = descriptionString
              return newTire
      
      #your original sample input     
      descriptions = ['285/30/18', '285/30/19', '235/40/17', '315/25/19', '275/30/19']
      
      #now lets make some real tire objects from those
      tires = [Tire.fromDescription(each) for each in descriptions]
      
      #make sure they still print
      [print(each.description) for each in tires]
      
      print('original sort')
      [print(each.description) for each in sorted(tires, key = attrgetter('radius'))]
      
      print('reversed original sort')
      [print(each.description) for each in sorted(tires, key = attrgetter('radius'), reverse = True)]
      
      print('width sort')
      [print(each.description) for each in sorted(tires, key = attrgetter('width'), reverse = True)]
      
      print('radius>>width>>profile sort')
      [print(each.description) for each in sorted(tires, key = attrgetter('radius', 'width', 'profile'))]
      

      希望这种方法的价值在最后是显而易见的。我们预先付出更大的代价(就代码空间而言)来具体化轮胎对象。但是一旦有了,我们就可以开始疯狂地对它们进行各种排序。考虑到将字符串表示和所需的排序输出相结合的某些假设,最初提出的算法工作得很好。但是,如果您需要更改排序输出,根据最后一行(按字段 3、1、2 排序),那么方便的元组反向技巧将不再起作用。将“它是什么”与您将如何呈现(排序)分开会更好(IMO)。之后你可能会想到一些更聪明的事情来处理它们,而不仅仅是对它们进行排序。

      【讨论】:

      • 它实际上是一个小型的 Django 应用程序。我现在知道对特定数据集进行排序的最佳方法,下一步实际上是在 models.py 中实现它,或者可能根据请求对其进行排序并将排序后的数据作为序列化的 json 集返回。这是一个很好的开始,感谢您的意见。
      【解决方案5】:

      如果/s的位置不变,试试:

      sorted(a, key=lambda x:x[-2:]+x[4:6]+x[:3])
      

      http://ideone.com/M6X6pW

      【讨论】:

        【解决方案6】:
            python 3.2
        
            sorted(list1,key=lambda x:x[-2:])
        

        【讨论】:

          【解决方案7】:

          此 Q/A 为我提供了解决我自己问题的指示 - 添加以让其他人知道。
          具有这种格式的 *nix 目录列表: /home/0000/Maildir/&lt;0-255&gt;/&lt;userdirs&gt;

          0000 - 四位数的唯一提供商名称
          - 范围

          列表大小从 3000 到 250000 个不等。

          我需要在第四个字段上使用数字排序对我的列表进行排序,在每个项目中用“/”分隔

          sorted(a, key=lambda y: int(y.split("/")[4]))
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-12-08
            • 1970-01-01
            • 2019-08-26
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多