List replication operator

Rob Gaddi rgaddi at highlandtechnology.invalid
Fri May 25 13:41:08 EDT 2018


On 05/25/2018 10:13 AM, bartc wrote:
> On 25/05/2018 17:58, Rob Gaddi wrote:
> 
>> So, in the spirit of explicit being better than implicit, please 
>> assume that for actual implementation replicate would be a static 
>> method of actual list, rather than the conveniently executable hackjob 
>> below.
>>
>> _list = list
>> _nodefault = object()
>>
>> class list(_list):
>>    @staticmethod
>>    def replicate(*n, fill=_nodefault, call=list):
> 
> That seems to work, but the dimensions are created in reverse order to 
> what I expected. Which is to have the order of indices corresponding to 
> the order of dimensions. So:
> 
>   x=list.replicate(2,3,4)
> 
>   print (len(x))
>   print (len(x[0]))
>   print (len(x[0][0]))
> 
> Gives output of 4, 3, 2 rather than 2, 3, 4.
> 
> Which means that x[0][0][3] is a bounds error.
> 

A fair point.  Something about multidimensional arrays always makes me 
semi-dyslexic.  And there I was wondering why making it work right had 
required I rip dimensions off the list from the end instead.

Corrected version below.  list.replicate(3, 2) now means "3 of 2 of 
this" as one would expect.  This is one of those days when doctest is my 
favorite thing about Python.

_list = list
_nodefault = object()

class list(_list):
   @staticmethod
   def replicate(*n, fill=_nodefault, call=list):
     """Return a list of specified dimensions.

     Fill and call can be used to prime the list with initial values, the
     default is to create a list of empty lists.

     Parameters:
       n : List of dimensions
       fill: If provided, the fill object is used in all locations.
       call: If fill is not provided, the result of call (a function of
       no arguments) is used in all locations.

     Example:
       >>> a = list.replicate(3, 2)
       >>> a
       [[[], []], [[], []], [[], []]]
       >>> a[0][0].append('a')
       >>> a
       [[['a'], []], [[], []], [[], []]]

       >>> b = list.replicate(3, 2, fill=[])
       >>> b
       [[[], []], [[], []], [[], []]]
       >>> b[0][0].append('a')
       >>> b
       [[['a'], ['a']], [['a'], ['a']], [['a'], ['a']]]

       >>> c = list.replicate(3, 2, call=dict)
       >>> c
       [[{}, {}], [{}, {}], [{}, {}]]
       >>> c[0][0]['swallow'] = 'unladen'
       >>> c
       [[{'swallow': 'unladen'}, {}], [{}, {}], [{}, {}]]

       >>> d = list.replicate(3, 2, fill=0)
       >>> d
       [[0, 0], [0, 0], [0, 0]]
       >>> d[0][0] = 5
       >>> d
       [[5, 0], [0, 0], [0, 0]]
     """

     if n:
       this = n[0]
       future = n[1:]
       return [
         list.replicate(*future, fill=fill, call=call)
           for _ in range(this)
       ]
     elif fill is _nodefault:
       return call()
     else:
       return fill


-- 
Rob Gaddi, Highland Technology -- www.highlandtechnology.com
Email address domain is currently out of order.  See above to fix.



More information about the Python-list mailing list