I want to rotate k element in a list in python. For example, n = 7, k = 3, and the array [1,2,3,4,5,6,7] is rotated to [5,6,7,1,2,3,4].
Here is the statement I wrote. It seems to work in the command line.
nums = nums[k%len(nums):] + nums[:k%len(nums)]
But when I encapsulate it in a function like:
def rotate(nums, k):
nums = nums[k%len(nums):] + nums[:k%len(nums)]
return
I want to modify nums directly, but this function doesn't work.
I know that I can use a for loop like:
for i in range(k):
nums.insert(0,nums.pop())
but I want to know why the previous method doesn't work?
What you want is a slice assignment:
nums[:] = nums[k%len(nums):] + nums[:k%len(nums)]
This mutates the list that was passed in, so the change is visible after the function returns. Assigning just to nums merely makes nums point to a different list inside the function; it doesn't affect the original list.
Are you sure you want to modify nums? You need not create a separate list even if you do not modify nums. One advantage of the following approach is that it will work with any sequence.
from itertools import islice
def rotate(lst, k):
n = len(lst)
start = n - (k % n) #handle all ints
for item in islice(lst, start, None):
yield item
for item in islice(lst, 0, start):
yield item
If you insist on modifying nums as you say, you can still do so. E.g.,
nums = [x + 1 for x in range(7)]
nums[:] = rotate(nums,-10)
The nums that is inside the function is only within that function. So you need to return it from that function. One way is like this (python 2.7 code, add parentheses to print if you use 3.x):
nums = [1, 2, 3, 4, 5, 6, 7]
k = 3
def rotate(nums, k):
return nums[k%len(nums):] + nums[:k%len(nums)]
print 'Original', nums
nums = rotate(nums, k)
print 'Rotated', nums
Related
I have the below code for a card game, it should remove the N number of cars from the given card list and return a tuple with 2 lists, the first list is the N objects from the original list and the secons list is the remaining cards not extracted from the original list.
lista_cartas = [1,2,3,4,5,6,7,8]
lista_N = []
N = 5
for i in range(N):
extracto = lista_cartas.pop(0)
lista_N.append(extracto)
lista_final = [lista_N, lista_cartas]
print(tuple(lista_final))
([1, 2, 3, 4, 5], [6, 7, 8])
it's working as I want but I need to trasform this into a function that takes the N number and the list as parameters, how can I achieve this?
is this somethinhg valid? or how can I make the function to take a list?
def sacar_cartas(N, lista=[]):
for i in range(N):
extracto = lista_cartas.pop(0)
lista_N.append(extracto)
lista_final = [lista_N, lista_cartas]
print(tuple(lista_final))
You can rework your solution entirely by using list slices:
lista_cartas = [1,2,3,4,5,6,7,8]
def sacar_cartas(todas_cartas, N):
return todas_cartas[:N], todas_cartas[N:]
such that sacar_cartas(lista_cartas, 5) results in the tuple:
([1, 2, 3, 4, 5], [6, 7, 8])
Notice how we can avoid the explicit tuple call by instead returning comma-separated values.
simple conversion:
def sacar_cartas(N, lista):
lista_N = []
for i in range(N):
extracto = lista.pop(0)
lista_N.append(extracto)
return tuple([lista_N, lista])
print(sacar_cartas(5, [1,2,3,4,5,6,7,8]))
Slightly reworked your code so that the function won't alter the passed in list (because of the lista_cartas.copy() call. As to your code and question, Python functions can accept a list as a variable without telling it that it is a list.
lista_cartas = [1,2,3,4,5,6,7,8]
def sacar_cartas(N, lista_cartas):
lista_N = []
lista_ct = lista_cartas.copy()
for i in range(N):
extracto = lista_ct.pop(0)
lista_N.append(extracto)
lista_final = [lista_N, lista_ct]
return lista_final
sacar_cartas(5, lista_cartas)
Python is duck typed. You can pass a list in just like any other variable, without having to define the type:
def function(some_variable):
for element in some_variable:
print(element)
function(['1st element', '2nd element', '3rd element'])
# prints:
# 1st element
# 2nd element
# 3rd element
Doing this:
def function(some_variable=[]):
Does NOT indicate that this variable is a list and is not needed. It instead tells the function that if you do not pass this variable in, it will default to the value []
You don't necessarily have to give a list a default value of empty. You can pass a list to a function by mentioning its variable name:
lista_cartas = [1,2,3,4,5,6,7,8]
lista_N = []
def sacar_cartas(N, lista_cartas, lista_N):
for i in range(N):
extracto = lista_cartas.pop(0)
lista_N.append(extracto)
lista_final = [lista_N, lista_cartas]
print(tuple(lista_final))
# Call the function for it to work
sacar_cartas(N = 5, lista_cartas, lista_N)
You can define variable within the function call if you want. Thats optional because you can define it like a list before the call.
I have a question I need to solve using python, using a def function. Basically take a list of numbers, and then and add a letter at the end of each element in the list.
I was finally able to do it, but for various reasons I need to find an alternative way that does not use enumerate. Is there any way to make this work without using enumerate function, something simpler. Here is my working code:
def addletter( mylist ):
for index, item in enumerate(mylist):
mylist[index] = str(item)
for i in range(len(mylist)):
mylist[i] = mylist[i] + randomletter
return
# Now you can call addletter function
mylist = [1,2,3,4,5,6,7,8,9,];
randomletter= 'a'
addletter( mylist );
print (mylist)
Done without the enumerate function:
(you can remove the other loop, and you don't have to call return, python will automatically return None):
def add_letter(mylist):
for i in range(len(mylist)):
mylist[i] = str(mylist[i]) + randomletter
# Now you can call addletter function
mylist = [1, 2, 3, 4, 5, 6, 7, 8, 9, ];
randomletter = 'a'
add_letter(mylist)
print(mylist)
def digit_sum(n):
n = str(n)
empty = [x.split() for x in n]
print empty
digit_sum(21)
This code will output:
[['2'], ['1']]
What I need is to make it:
[2, 1]
so I can add the numbers in the list together. How do I do that?
I would just do (you don't need to .split it, just convert it to a string over which you can iterate):
def digit_sum(n):
empty = [int(d) for d in str(n)]
print empty
Demo:
>>> digit_sum(21)
[2, 1]
You could then obviously add them together with the sum() function.
Don't call split. Split tries to divide a string on whitespace (by default). It will return a list of strings always (even if there were no splits to be made).
Since your loop is over a string, x will be a single character. That means you'll never have any whitespace to split on.
Just do [x for x in n] or list(n).
Or if you want your digits as integers, rather than strings: [int(x) for x in n] or map(int, n)
I believe if you
firstlist.append(secondlist)
Python should print 1, 2. Posting from a Windows Phone, so I can't run the code, excuse my incompetence if this doesn't work.
This works:
def digit_sum(n):
n = str(n)
empty = [int(x) for x in n]
print empty
digit_sum(21)
Output:
[2,1]
split returns a list. for x in n will go over each character in the string and int(x) converts the character to an integer.
>>> from itertools import chain
>>> x = [['2'], ['1']]
>>> map(int, chain(*x))
[2, 1]
If you want to completely flatten a list of lists, you need to check if its iterable.
To do this you can create a generator which returns a non-iterable item, or recursively calls itself if the item is iterable.
Then place each element of the generator in a list, and print it.
Warning!!
This will crash with cycling lists ie l = []; l.append(l)
def get_single_elements(item):
if hasattr(item, '__iter__'):
for child_item in item:
for element in get_single_elements(child_item):
yield element
else:
yield item
def print_flat(item):
print [element for element in get_single_elements(item)]
>>> print_flat([[[0],[1]]])
[0, 1]
>>> print_flat([[[[[0,[1,2,[3,4]]]]],[[1]]]])
[0, 1, 2, 3, 4, 1]
Edit if you're sure you want to convert all items to ints, then write it like this
def print_flat(item):
print [int(element) for element in get_single_elements(item)]
I am a student in an intro-level python class, and my task is to define "reverse(mylist)" using while loop
This is what I have so far:
def reverse(mylist):
a=0
b=len(mylist)
xlist=mylist
while(a!=b):
mylist[a]=xlist[(-a)-1]
a+=1
return mylist
Let's say the input list is [1,2,3,4,5,6], and using my reverse function I will get the output [6, 5, 4, 4, 5, 6]... And [1,2,3,4,5] will become [5,4,3,4,5]
I am not sure what I am doing wrong here.
Following statement makes both xlist, mylist reference same list object:
xlist = mylist
You need to copy it.
xlist = mylist[:]
BTW, using for loop, you don't need to increment a manually:
for a in range(len(mylist)):
....
def reverse(mylist):
a=0
b=len(mylist)
xlist=[]
while(a!=b):
mylist[a:a]=xlist[(-a)-1]
a+=1
return mylist
list is transfered by referance not by value.
you need to create new list.
"xlist = mylist" only create a referance.
ps
"for in" is more commonly used in python.
for i in range(2, -1, -1):
xlist.append(mylist[i])
or:
xlist = [mylist[i], for i in range(2, -1, -1) ]
I'm new in Python but basically I want to create sub-groups of element from the list with a double loop, therefore I gonna compare the first element with the next to figure out if I can create these sublist, otherwise I will break the loop inside and I want continue with the last element but in the main loop:
Example: 5,7,8,4,11
Compare 5 with 7, is minor? yes so include in the newlist and with the inside for continue with the next 8, is minor than 5? yes, so include in newlist, but when compare with 4, I break the loop so I want continue in m with these 4 to start with the next, in this case with 11...
for m in xrange(len(path)):
for i in xrange(m+1,len(path)):
if (path[i] > path[m]):
newlist.append(path[i])
else:
break
m=m+i
Thanks for suggestions or other ideas to achieve it!
P.S.
Some input will be:
input: [45,78,120,47,58,50,32,34]
output: [45,78,120],[47,58],50,[32,34]
The idea why i want make a double loops due to to compare sub groups of the full list,in other way is while 45 is minor than the next one just add in the new list, if not take the next to compare in this case will be 47 and start to compare with 58.
No loop!
Well at least, no explicit looping...
import itertools
def process(lst):
# Guard clause against empty lists
if len(lst) < 1:
return lst
# use a dictionary here to work around closure limitations
state = { 'prev': lst[0], 'n': 0 }
def grouper(x):
if x < state['prev']:
state['n'] += 1
state['prev'] = x
return state['n']
return [ list(g) for k, g in itertools.groupby(lst, grouper) ]
Usage (work both with Python 2 & Python 3):
>>> data = [45,78,120,47,58,50,32,34]
>>> print (list(process(data)))
[[45, 78, 120], [47, 58], [50], [32, 34]]
Joke apart, if you need to group items in a list itertools.groupby deserves a little bit of attention. Not always the easiest/best answer -- but worth to make a try...
EDIT: If you don't like closures -- and prefer using an object to hold the state, here is an alternative:
class process:
def __call__(self, lst):
if len(lst) < 1:
return lst
self.prev = lst[0]
self.n = 0
return [ list(g) for k, g in itertools.groupby(lst, self._grouper) ]
def _grouper(self, x):
if x < self.prev:
self.n += 1
self.prev = x
return self.n
data = [45,78,120,47,58,50,32,34]
print (list(process()(data)))
EDIT2: Since I prefer closures ... but #torek don't like the dictionary syntax, here a third variation around the same solution:
import itertools
def process(lst):
# Guard clause against empty lists
if len(lst) < 1:
return lst
# use an object here to work around closure limitations
state = type('State', (object,), dict(prev=lst[0], n=0))
def grouper(x):
if x < state.prev:
state.n += 1
state.prev = x
return state.n
return [ list(g) for k, g in itertools.groupby(lst, grouper) ]
data = [45,78,120,47,58,50,32,34]
print (list(process(data)))
I used a double loop as well, but put the inner loop in a function:
#!/usr/bin/env python
def process(lst):
def prefix(lst):
pre = []
while lst and (not pre or pre[-1] <= lst[0]):
pre.append(lst[0])
lst = lst[1:]
return pre, lst
res=[]
while lst:
subres, lst = prefix(lst)
res.append(subres)
return res
print process([45,78,120,47,58,50,32,34])
=> [[45, 78, 120], [47, 58], [50], [32, 34]]
The prefix function basically splits a list into 2; the first part is composed of the first ascending numbers, the second is the rest that still needs to be processed (or the empty list, if we are done).
The main function then simply assembles the first parts in a result lists, and hands the rest back to the inner function.
I'm not sure about the single value 50; in your example it's not in a sublist, but in mine it is. If it is a requirement, then change
res.append(subres)
to
res.append(subres[0] if len(subres)==1 else subres)
print process([45,78,120,47,58,50,32,34])
=> [[45, 78, 120], [47, 58], 50, [32, 34]]
#uselpa's version is fine. Here's mine (same issue with [50] instead of just 50) that uses collections.deque to be a little more efficient, and also some long comments...
#! /usr/bin/env python
from collections import deque
def process(lst):
"""
Given a list of values that is not sorted (such that for some
valid indices i,j, i<j, sometimes lst[i] > lst[j]), produce a
new list-of-lists, such that in the new list, each sublist *is*
sorted:
for all sublist \elem returnval:
assert_is_sorted(sublist)
and furthermore this is the minimal set of sublists required
to achieve the condition.
Thus, if the input list lst is actually sorted, this returns
[list(lst)].
"""
def sublist(deq):
"""
Pop items off the front of deque deq until the next one
goes backwards. Return the constructed sub-list.
"""
sub = [deq.popleft()]
while deq and deq[0] >= sub[-1]:
sub.append(deq.popleft())
return sub
# Make a copy of lst before modifying it; use a deque so that
# we can pull entries off it cheaply.
deq = deque(lst)
output = []
ret = []
while deq:
ret.append(sublist(deq))
return ret
print process([45,78,120,47,58,50,32,34])
(Incidentally, in the days before collections.deque I'd probably just use a reversed copy of lst and use lst.pop() in sublist. That's not quite as obvious, though.)
why not simply use a single for loop instead of using itertool and all fancy stuff.
def list_test(inlist, outlist):
if not inlist:
return []
prev=inlist[0]
x=[]
for item in inlist:
if item >= prev:
x.append(item)
else:
outlist.append(x)
x=[]
x.append(item)
prev=item
if x:
outlist.append(x)
in_list=[1,0,1,2,3]
out_list = []
list_test(in_list, out_list)
print(out_list)
O/p:[[1], [0, 1, 2, 3]]