Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing python slice notation

I'm trying to reimplement python slice notation in another language (php) and looking for a snippet (in any language or pseudocode) that would mimic the python logic. That is, given a list and a triple (start, stop, step) or a part thereof, determine correct values or defaults for all parameters and return a slice as a new list.

I tried looking into the source. That code is far beyond my c skills, but I can't help but agree with the comment saying:

/* this is harder to get right than you might think */ 

Also, if something like this is already done, pointers will be greatly appreciated.

This is my test bench (make sure your code passes before posting):

#place your code below
code = """
def mySlice(L, start=None, stop=None, step=None):
or 
<?php function mySlice($L, $start=NULL, $stop=NULL, $step=NULL) ...
or 
function mySlice(L, start, stop, step) ...
"""

import itertools

L = [0,1,2,3,4,5,6,7,8,9]

if code.strip().startswith('<?php'):
     mode = 'php'

if code.strip().startswith('def'):
     mode = 'python'

if code.strip().startswith('function'):
     mode = 'js'

if mode == 'php':
    var, none = '$L', 'NULL'
    print code, '\n'
    print '$L=array(%s);' % ','.join(str(x) for x in L)
    print "function _c($s,$a,$e){if($a!==$e)echo $s,' should be [',implode(',',$e),'] got [',implode(',',$a),']',PHP_EOL;}"

if mode == 'python':
    var, none = 'L', 'None'
    print code, '\n'
    print 'L=%r' % L
    print "def _c(s,a,e):\n\tif a!=e:\n\t\tprint s,'should be',e,'got',a"

if mode == 'js':
    var, none = 'L', 'undefined'
    print code, '\n'
    print 'L=%r' % L
    print "function _c(s,a,e){if(a.join()!==e.join())console.log(s+' should be ['+e.join()+'] got ['+a.join()+']');}"


print

n = len(L) + 3
start = range(-n, n) + [None, 100, -100]
stop  = range(-n, n) + [None, 100, -100]
step  = range(-n, n) + [100, -100]

for q in itertools.product(start, stop, step): 

    if not q[2]: q = q[:-1]

    actual = 'mySlice(%s,%s)' % (var, ','.join(none if x is None else str(x) for x in q))
    slice_ = 'L[%s]' % ':'.join('' if x is None else str(x) for x in q)
    expect = eval(slice_)

    if mode == 'php':
        expect = 'array(%s)' % ','.join(str(x) for x in expect)
        print "_c(%r,%s,%s);" % (slice_, actual, expect)

    if mode == 'python':
        print "_c(%r,%s,%s);" % (slice_, actual, expect)

    if mode == 'js':
        print "_c(%r,%s,%s);" % (slice_, actual, expect)

how to use it:

  • save into a file (test.py)
  • place your python, php or javascript code between """s
  • run python test.py | python or python test.py | php or python test.py | node
like image 771
georg Avatar asked Aug 29 '12 08:08

georg


People also ask

How do you use slice notation in Python?

Basic Usage of Slices The full slice syntax is: start:stop:step. start refers to the index of the element which is used as a start of our slice. stop refers to the index of the element we should stop just before to finish our slice. step allows you to take each nth-element within a start:stop range.

When slicing in Python What does the 2 in [:: 2 specify?

Second note, when no start is defined as in A[:2] , it defaults to 0. There are two ends to the list: the beginning where index=0 (the first element) and the end where index=highest value (the last element).

When slicing in Python What does the 0 in this statement 0 2 specify?

The index of the slice is specified in [start:stop] . Remember Python counting starts at 0 and ends at n-1 . The index [0:2] pulls the first two values out of an array.

What is list slicing in Python with example?

It's possible to "slice" a list in Python. This will return a specific segment of a given list. For example, the command myList[2] will return the 3rd item in your list (remember that Python begins counting with the number 0).


2 Answers

Here's a straight port of the C code:

def adjust_endpoint(length, endpoint, step):
     if endpoint < 0:
         endpoint += length
         if endpoint < 0:
             endpoint = -1 if step < 0 else 0
     elif endpoint >= length:
         endpoint = length - 1 if step < 0 else length
     return endpoint

def adjust_slice(length, start, stop, step):
     if step is None:
         step = 1
     elif step == 0:
         raise ValueError("step cannot be 0")

     if start is None:
         start = length - 1 if step < 0 else 0
     else:
         start = adjust_endpoint(length, start, step)

     if stop is None:
         stop = -1 if step < 0 else length
     else:
         stop = adjust_endpoint(length, stop, step)

     return start, stop, step

def slice_indices(length, start, stop, step):
     start, stop, step = adjust_slice(length, start, stop, step)
     i = start
     while (i > stop) if step < 0 else (i < stop):
         yield i
         i += step

def mySlice(L, start=None, stop=None, step=None):
     return [L[i] for i in slice_indices(len(L), start, stop, step)]
like image 157
ecatmur Avatar answered Oct 03 '22 02:10

ecatmur


This is what I came up with (python)

def mySlice(L, start=None, stop=None, step=None):
    answer = []
    if not start:
        start = 0
    if start < 0:
        start += len(L)

    if not stop:
        stop = len(L)
    if stop < 0:
        stop += len(L)

    if not step:
        step = 1

    if stop == start or (stop<=start and step>0) or (stop>=start and step<0):
        return []

    i = start
    while i != stop:
        try:
            answer.append(L[i])
            i += step
        except:
            break
    return answer

Seems to work - let me know what you think

Hope it helps

like image 36
inspectorG4dget Avatar answered Oct 03 '22 03:10

inspectorG4dget