python: convert “5,4,2,4,1,0” into [[5, 4], [2, 4], [1, 0]]

后端 未结 11 1065
梦如初夏
梦如初夏 2020-11-28 15:33

Is there a \"straightforward\" way to convert a str containing numbers into a list of [x,y] ints?

# from: \'5,4,2,4,1,0,3,0,5,1,3,3,14,32,3,5\'
# to: [[5, 4         


        
相关标签:
11条回答
  • 2020-11-28 15:44

    You can shorten the first part (converting "1,2,3" to [1, 2, 3]) by using the split function:

    num_list = num_str.split(",")
    

    There might be an easier way to get pairs, but I'd do something like this:

    xy_pairs = []
    for i in range(0, len(num_list), 2):
        x = num_list[i]
        y = num_list[i + 1]
        xy_pairs.append([x, y])
    

    Also, since these are all lists of a defined length (2), you should probably use a tuple:

    xy_pairs.append((x, y))
    
    0 讨论(0)
  • 2020-11-28 15:44

    It may be interesting to have a generator. Here's a generator expression:

    import re
    ch = '5,4,2,4,1,0,3,0,5,1,3,3,14,32,3,5'
    genexp = ( map(int,ma.groups()) for ma in re.finditer('(\d+)\s*,\s*(\d+)',ch) )
    
    0 讨论(0)
  • 2020-11-28 15:46

    Maybe this?

    a = "0,1,2,3,4,5,6,7,8,9".split(",")
    [[int(a.pop(0)), int(a.pop(0))] for x in range(len(a)/2)]
    
    0 讨论(0)
  • 2020-11-28 15:47
    #!/usr/bin/env python
    
    from itertools import izip
    
    def pairwise(iterable):
        "s -> (s0,s1), (s2,s3), (s4, s5), ..."
        a = iter(iterable)
        return izip(a, a)
    
    s = '5,4,2,4,1,0,3,0,5,1,3,3,4,3,3,5'
    fields = s.split(',')
    print [[int(x), int(y)] for x,y in pairwise(fields)]
    

    Taken from @martineau's answer to my question, which I have found to be very fast.

    Output:

    [[5, 4], [2, 4], [1, 0], [3, 0], [5, 1], [3, 3], [4, 3], [3, 5]]
    
    0 讨论(0)
  • 2020-11-28 15:48

    There are two important one line idioms in Python that help make this "straightforward".

    The first idiom, use zip(). From the Python documents:

    The left-to-right evaluation order of the iterables is guaranteed. This makes possible an idiom for clustering a data series into n-length groups using zip(*[iter(s)]*n).

    So applying to your example:

    >>> num_str = '5,4,2,4,1,0,3,0,5,1,3,3,14,32,3,5'
    >>> zip(*[iter(num_str.split(","))]*2)
    [('5', '4'), ('2', '4'), ('1', '0'), ('3', '0'), ('5', '1'), 
    ('3', '3'), ('14', '32'), ('3', '5')]
    

    That produces tuples each of length 2.

    If you want the length of the sub elements to be different:

    >>> zip(*[iter(num_str.split(","))]*4)
    [('5', '4', '2', '4'), ('1', '0', '3', '0'), ('5', '1', '3', '3'), 
    ('14', '32', '3', '5')]
    

    The second idiom is list comprehensions. If you want sub elements to be lists, wrap in a comprehension:

    >>> [list(t) for t in zip(*[iter(num_str.split(","))]*4)]
    [['5', '4', '2', '4'], ['1', '0', '3', '0'], ['5', '1', '3', '3'], 
    ['14', '32', '3', '5']]
    >>> [list(t) for t in zip(*[iter(num_str.split(","))]*2)]
    [['5', '4'], ['2', '4'], ['1', '0'], ['3', '0'], ['5', '1'], ['3', '3'], 
    ['14', '32'], ['3', '5']]
    

    Any sub element groups that are not complete will be truncated by zip(). So if your string is not a multiple of 2, for example, you will loose the last element.

    If you want to return sub elements that are not complete (ie, if your num_str is not a multiple of the sub element's length) use a slice idiom:

    >>> l=num_str.split(',')
    >>> [l[i:i+2] for i in range(0,len(l),2)]
    [['5', '4'], ['2', '4'], ['1', '0'], ['3', '0'], ['5', '1'], 
    ['3', '3'], ['14', '32'], ['3', '5']]
    >>> [l[i:i+7] for i in range(0,len(l),7)]
    [['5', '4', '2', '4', '1', '0', '3'], ['0', '5', '1', '3', '3', '14', '32'], 
    ['3', '5']]
    

    If you want each element to be an int, you can apply that prior to the other transforms discussed here:

    >>> nums=[int(x) for x in num_str.split(",")]
    >>> zip(*[iter(nums)]*2)
    # etc etc etc
    

    As pointed out in the comments, with Python 2.4+, you can also replace the list comprehension with a Generator Expression by replacing the [ ] with ( ) as in:

     >>> nums=(int(x) for x in num_str.split(","))
     >>> zip(nums,nums)
     [(5, 4), (2, 4), (1, 0), (3, 0), (5, 1), (3, 3), (14, 32), (3, 5)]
     # or map(list,zip(nums,nums)) for the list of lists version...
    

    If your string is long, and you know that you only need 2 elements, this is more efficient.

    0 讨论(0)
  • 2020-11-28 15:48

    This is a more generalized function which works for different chunk sizes and appends the reminder if needed

    def breakup(mylist,chunks):
      mod = len(mylist) % chunks
      if mod ==  0:
          ae = []
      elif mod == 1:
          ae = mylist[-1:]
      else:
          ae = [tuple(mylist[-mod:])]
      return zip(*[iter(mylist)]*chunks) + ae
    
    num_str = '5,4,2,4,1,0,3,0,5,1,3,3,14,32,3,5'
    lst = map(int,num_str.split(','))
    print breakup(lst,2)
    

    OUT: [(5, 4), (2, 4), (1, 0), (3, 0), (5, 1), (3, 3), (14, 32), (3, 5)]

    0 讨论(0)
提交回复
热议问题