list inside list python - python

I am not looking to get an list inside list instead I just want to add zeros but do not know how. see code
def myconv(x,h):
q=[]
print(h)
for i in range(len_h):
q.append(h[len_h-1-i])
print(q)
q.insert(0,([0]*len_h)) #I want this to add just plain zeros to the array... not an array insdie an
#like it is doing here
q.insert(len(q)+1,(0]*len_h))
print(q)
print(myconv([6,7,8,9],[1,2,3,4,5,6,7,8,9,0]))

You want to use +, e.g. [0, 0, 0] + [2, 1, 3] == [0, 0, 0, 2, 1, 3], to concatenate an array onto the first. Otherwise, you'll need to insert (or append) items one at a time.

To demonstrate how list multiplication works:
>>> [0]*2
[0, 0]
>>> [0]*5
[0, 0, 0, 0, 0]
I prefer the in-place extend operation. Just don't assign to it, because like most all Python in-place methods, it returns None.
>>> l2.extend([0]*5)
>>> l2
[1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0]

You have two ways of doing this:
q = [0]*len_h + q
or
q[0:0] = [0]*len_h

q.insert(0,([0]*len_h))
This creates a list within a list because [0]*len_h creates a new list. This array is then inserted into q. Instead, insert each element into q without creating a new list.
for i in range(len_h):
q.insert(0, 0)

Related

Is it possible to add the output of a generator when making a list in Python?

Is it possible to make a generator's output be added into a list creation, without making a nested list in Python?
I have tried the following code, but it only gives me a generator object, and not the items.
x = 5
expected_list = [3, 0, 0, 0, 0, 0, 3]
list = [3, 0 for i in range(x), 3]
print(list)
I get this error whenever trying to run this code:
list = [3, 0 for i in range(x), 3]
^^^^
SyntaxError: did you forget parentheses around the comprehension target?
If I put parentheses around 0 for i in range(x), I get the list
[3, <generator object <genexpr> at 0x000001A065179A10>, 3]
I would like for the generator object to return 0, 0, 0, 0, 0, without creating a list inside of my list.
Unpack it:
[3, *(0 for i in range(x)), 3]

Move zeroes to end of list

I am working on moving all zeroes to end of list. .. is this approach bad and computationally expensive?
a = [1, 2, 0, 0, 0, 3, 6]
temp = []
zeros = []
for i in range(len(a)):
if a[i] !=0:
temp.append(a[i])
else:
zeros.append(a[i])
print(temp+zeros)
My Program works but not sure if this is a good approach?
A sorted solution that avoids changing the order of the other elements is:
from operator import not_
sorted(a, key=not_)
or without an import:
sorted(a, key=lambda x: not x) # Or x == 0 for specific numeric test
By making the key a simple boolean, sorted splits it into things that are truthy followed by things that are falsy, and since it's a stable sort, the order of things within each category is the same as the original input.
This looks like a list. Could you just use sort?
a = [1, 2, 0, 0, 0, 3, 6]
a.sort(reverse=True)
a
[6, 3, 2, 1, 0, 0, 0]
To move all the zeroes to the end of the list while preserving the order of all the elements in one traversal, we can keep the count of all the non-zero elements from the beginning and swap it with the next element when a non-zero element is encountered after zeroes.
This can be explained as:
arr = [18, 0, 4, 0, 0, 6]
count = 0
for i in range(len(arr):
if arr[i] != 0:
arr[i], arr[count] = arr[count], arr[i]
count += 1
How the loop works:
when i = 0, arr[i] will be 18, so according to the code it will swap with itself, which doesn't make a difference, and count will be incremented by one. When i=1, it will have no affect as till now the list we have traversed is what we want(zero in the end). When i=4, arr[i]= 4 and arr[count(1)]= 0, so we swap them leaving the list as[18, 4, 0, 0, 0, 6] and count becomes 2 signifying two non-zero elements in the beginning. And then the loop continues.
You can try my solution if you like
class Solution:
def moveZeroes(self, nums: List[int]) -> None:
for num in nums:
if num == 0:
nums.remove(num)
nums.append(num)
I have tried this code in leetcode & my submission got accepted using above code.
Nothing wrong with your approach, really depends on how you want to store the resulting values. Here is a way to do it using list.extend() and list.count() that preserves order of the non-zero elements and results in a single list.
a = [1, 2, 0, 0, 0, 3, 6]
result = [n for n in a if n != 0]
result.extend([0] * a.count(0))
print(result)
# [1, 2, 3, 6, 0, 0, 0]
You can try this
a = [1, 2, 0, 0, 0, 3, 6]
x=[i for i in a if i!=0]
y=[i for i in a if i==0]
x.extend(y)
print(x)
There's nothing wrong with your solution, and you should always pick a solution you understand over a 'clever' one you don't if you have to look after it.
Here's an alternative which never makes a new list and only passes through the list once. It will also preserve the order of the items. If that's not necessary the reverse sort solution is miles better.
def zeros_to_the_back(values):
zeros = 0
for value in values:
if value == 0:
zeros += 1
else:
yield value
yield from (0 for _ in range(zeros))
print(list(
zeros_to_the_back([1, 2, 0, 0, 0, 3, 6])
))
# [1, 2, 3, 6, 0, 0, 0]
This works using a generator which spits out answers one at a time. If we spot a good value we return it immediately, otherwise we just count the zeros and then return a bunch of them at the end.
yield from is Python 3 specific, so if you are using 2, just can replace this with a loop yielding zero over and over.
Numpy solution that preserves the order
import numpy as np
a = np.asarray([1, 2, 0, 0, 0, 3, 6])
# mask is a boolean array that is True where a is equal to 0
mask = (a == 0)
# Take the subset of the array that are zeros
zeros = a[mask]
# Take the subset of the array that are NOT zeros
temp = a[~mask]
# Join the arrays
joint_array = np.concatenate([temp, zeros])
I tried using sorted, which is similar to sort().
a = [1, 2, 0, 0, 0, 3, 6]
sorted(a,reverse=True)
ans:
[6, 3, 2, 1, 0, 0, 0]
from typing import List
def move(A:List[int]):
j=0 # track of nonzero elements
k=-1 # track of zeroes
size=len(A)
for i in range(size):
if A[i]!=0:
A[j]=A[i]
j+=1
elif A[i]==0:
A[k]=0
k-=1
since we have to keep the relative order. when you see nonzero element, place that nonzero into the index of jth.
first_nonzero=A[0] # j=0
second_nonzero=A[1] # j=1
third_nonzero=A[2] # j=2
With k we keep track of 0 elements. In python A[-1] refers to the last element of the array.
first_zero=A[-1] # k=-1
second_zero=A[-2] # k=-2
third_zero= A[-3] # k=-3
a = [4,6,0,6,0,7,0]
a = filter (lambda x : x!= 0, a) + [0]*a.count(0)
[4, 6, 6, 7, 0, 0, 0]

pythonic way of appending to a list using for expression: looping the .append() action

Here is what I wanted to do: for-expression the .append() action, instead of doing a list comprehension of generator:
l = ['some existing elements']
l.append([0, 0, 0, n]) for n in range(10)
# this will give error
I somehow understand why my above code is wrong, see below:
l = [ [].append([0, 0, 0, n]) for n in range(10) ]
l
>>> [None, None, None, None, None, None, None, None, None, None]
# python is putting the result of expression "[].append([0,0,0,n])" 10 times in
# a list comprehension, instead of doing appending 10 times
I am wondering if we have something like DoIt_InsteadOfEvalutingIt( l.append([0,0,0,n]) ) for n in range(10)?
Am I wasting everyone's time? for-expression is ONLY for list comprehension or generator? may be this is where I should go old school, and just do (faster too probably):
l = ['some existing elements']
for n in range(10):
l.append([0, 0, 0, n])
# or
# use for expression to create the data, and append the data
l = ['some existing elements']
l.append([[0, 0, 0, n] for n in range(10)])
You can't use the generator/comprehension for syntax outside of a generator/comprehension (without using an explicit loop). But you can use a simple list comprehension to do what you want.
>>> [[0,0,0,n] for n in range(10)]
[[0, 0, 0, 0], [0, 0, 0, 1], ..., [0, 0, 0, 9]]
If you need to put all these on the end of an existing list, use extend:
existing_stuff = [1, 2, 3]
existing_stuff.extend([[0,0,0,n] for n in range(10)])
If you need to do something more complex in your loop, just use a normal for loop.
for n in range(10):
existing_stuff.append([0,0,0,n])
# other stuff
It seems you are missing square brackets in your second line. Cos the idea works if you like expressing it that way. Also append adds the whole list as an element to the list. What you need here is extend that instead will add every element from the list comprehension to the original list l:
l = [1, 2, 3, 4]
[l.extend([n, n + 1]) for n in range(5, 11, 2)]
print l
Output:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
At the end you suggested:
l = ['some existing elements']
l.append([[0, 0, 0, n] for n in range(10)])
I think this is a good idea, although you probably want to replace append with extend (I'm guessing you want the length of l to increase by 10, not 1).
You can make it shorter like so:
l = ['some existing elements'] + [[0, 0, 0, n] for n in range(10)]

How can I keep a vector in the same order after removing an element in Python

I know this seems like such a simple question, but when I go to remove the last element of my vector it reorders my vector and won't keep 0 as the last element.
vec = [1, 1, 0, 1]
vec.remove(vec[3])
The remaining vec is [1, 0, 1] when I wanted it to stay in order as [1, 1, 0]
Thanks!
vec = [1, 1, 0, 1]
vec.remove(vec[3])
vec[3] is 1, so you are removing the first element whose value is 1, i.e., the first element. The remaining elements are [1, 0, 1]. No reordering has been done. This would have been obvious if you had used a wider variety of values in your list.
You want one of these:
vec.pop(3)
del vec[3]

reverse() does not work on a Python literal?

Why doesn't this work in Python?
>>> print [0,1,0,1,1,0,1,1,1,0,1,1,1,1,0].reverse()
None
I expected to get back the list in reverse order.
>>> a = [3, 4, 5]
>>> print a.reverse()
None
>>> a
[5, 4, 3]
>>>
It's because reverse() does not return the list, rather it reverses the list in place. So the return value of a.reverse() is None which is shown in the print.
If you want it to return a new list in reverse order, you can use [::-1]
>>> [0,1,0,1,1,0,1,1,1,0,1,1,1,1,0][::-1]
[0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0]
As I'm still trying to understand the downvote, if it doesn't matter that the original list gets changed, use #taskinoor's answer, it'll be faster.
However if you're required to keep the original list unchanged, I suggest you to use [::-1].
from time import time
lst = [0,1,0,1,1,0,1,1,1,0,1,1,1,1,0]
s = time()
for i in xrange(5000000):
a = lst[::-1] # creates a reversed list
print time() -s
s = time()
for i in xrange(5000000):
b = lst[:] # copies the list
b.reverse() # reverses it
print time() -s
outputs
2.44950699806
3.02573299408
If you want reversed copy of a list, use reversed:
>>> list(reversed([1,2,3,4]))
[4, 3, 2, 1]
p.s. reversed returns an iterator instead of copy of a list (as [][::1] does). So it is suitable then you need to iterate through a reversed iterable. Additional list() here used only for the demonstration.
Just to complement other answers. Do not forget:
>> reversed_iterator = reversed([0,1,0,1,1,0,1,1,1,0,1,1,1,1,0])
>> print list(reversed_iterator)
[0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0]
This way your list is unchanged if this is a requierement.
reverse changes a list variable as seen here
list reverse
if you print it after you reversed it it will show up correctily
so just use a variable

Categories

Resources