Replace list number values with others? - python

I have this code
start_list = [5, 3, 1, 2, 4]
square_list = []
for number in start_list:
number = number**2
#I bet something should be added here but
#I have no idea what that would be
square_list.append(start_list[0])
square_list.append(start_list[1])
square_list.append(start_list[2])
square_list.append(start_list[3])
square_list.append(start_list[4])
square_list.sort()
print square_list
and I actually want to create a new list (the square_list) which includes the numbers of the start_list squared and sorted. This is my first day on python so be gentle!

Build a generator over the list producing your result, and feed it to sorted to get a list based on ascending value, eg:
start_list = [5, 3, 1, 2, 4]
square_list = sorted(n**2 for n in start_list)
# [1, 4, 9, 16, 25]

as I understand In your case it should looks like this:
start_list = [5, 3, 1, 2, 4]
square_list = []
for number in start_list:
number = number**2
square_list.append(number)
square_list.sort()
but You can use other methods
square_list = sorted(number**2 for number in start_list)
or
square_list = [number**2 for number in start_list]
square_list.sort()

Jon Clements' generator approach is the best and most pythonic way of doing this, however I think since you're a beginner it's worth understanding the for loop way of doing it. You've clearly understood the elements you need, you just need to plug them together in a new way.
start_list = [5, 3, 1, 2, 4]
square_list = []
for number in start_list:
All good so far, but you want to be adding these to square_list instead of doing number = number**2. Your code is simply modifying a temporary variable, rather than changing anything in place, assigning a new value to number won't change start_list. You want to this next:
square_list.append(number**2)
Then you just need to sort and print as you've already done
square_list.sort()
print(square_list)
(print without the brackets will work but it's being dropped with Python 3 so it's best to get used to using brackets now)

Related

Delete n occurrences of an element. Reorder list to match expected output

I was able to get the list to contain the correct number of occurrences for each element; however, the output I am getting is in the wrong order. So my question is: how would I reorder this to match the expected output? (Or write code that outputs what's expected. I would prefer help with fixing the code I wrote, however.)
My code:
def delete_nth(order,max_e):
for i in order:
if i in order:
if order.count(i)>max_e:
order.remove(i)
return order
My Inputs:
order = [1, 2, 3, 1, 1, 2, 1, 2, 3, 3, 2, 4, 5, 3, 1], max_e = 3
My output:
[1, 2, 1, 2, 3, 3, 2, 4, 5, 3, 1]
Should equal:
[1, 2, 3, 1, 1, 2, 2, 3, 3, 4, 5]
The prompt:
Alice and Bob were on a holiday. Both of them took many pictures of
the places they've been, and now they want to show Charlie their
entire collection. However, Charlie doesn't like these sessions,
since the motive usually repeats. He isn't fond of seeing the Eiffel
tower 40 times. He tells them that he will only sit during the
session if they show the same motive at most N times. Luckily, Alice
and Bob are able to encode the motive as a number. Can you help them
to remove numbers such that their list contains each number only up
to N times, without changing the order?
Task
Given a list lst and a number N, create a new list that contains each
number of lst at most N times without reordering. For example if N = 2, and the input is [1, 2, 3, 1, 2, 1, 2, 3], you take [1, 2, 3, 1, 2], drop the
next [1, 2] since this would lead to 1 and 2 being in the result 3
times, and then take 3, which leads to [1, 2, 3, 1, 2, 3].
Let's take a look at your code first:
def delete_nth(order, max_e):
for i in order:
if i in order: # this is (or should be) redundant
if order.count(i) > max_e: # note this scans order many times
order.remove(i) # removes the "first" occurrence not the current
return order
Word of warning, removing items from a list while iterating over it is full of pitfalls. For example after we do a remove() and go to the next iteration, are we sure what the "next" i is going to be?
anyways, the main problem is we are removing the items from the start of the list rather than from the end of it. There is also the issue of scanning items many times but we can look at that later.
One option then might be to work on a reversed version of the list:
NOTE: do not use delete_nth_v2() it is just here to illustrate a point
def delete_nth_v2(order, max_e):
order_reversed = list(reversed(order))
for i in order_reversed:
if order_reversed.count(i) > max_e:
order_reversed.remove(i)
return list(reversed(order_reversed))
This looks like it will do the trick a little better, but we actually still have the problem that i is likely NOT what we expect it to be.
to see this, add in a print() statement:
def delete_nth_v2(order, max_e):
order_reversed = list(reversed(order))
for i in order_reversed:
print(i, order_reversed)
if order_reversed.count(i) > max_e:
order_reversed.remove(i)
return list(reversed(order_reversed))
delete_nth_v2([1,2,3,1,2,3,1,2,3,4], 2)
you will see that on the 3rd iteration, we skip what we might have hoped was i == 2 Bummer :-(
Perhaps though there is a way we can track indexes more manually ourselves. This might allow us to also avoid reversing the lists
def delete_nth_v3(order, max_e):
for index in range(len(order) -1, -1, -1):
if order.count(order[index]) > max_e:
order.pop(index)
return order
Now we are getting someplace. This even produces the "correct" result :-) This seems better and is inline with how we started, but there is still the nagging opportunity to not search the entire list for each item in the list.
Why don't we just build a new list while keeping track of how many of each item we have already seen. This trades a little extra space to avoid the repeated searches.
def delete_nth_v4(items, at_most):
counts = {}
keepers = []
for item in items:
if counts.setdefault(item, 0) + 1 <= at_most:
counts[item] += 1
keepers.append(item)
return keepers
Again we get the correct result and this time it is potentially much faster (at least with larger lists) :-)
Finally, if it was me, I would duck being responsible for the space of the "new" list and I would look at yielding the results back to the caller. I would also probably swap out setdefault() for a collections.defaultdict()
import collections
def delete_nth_v5(items, at_most):
counts = collections.defaultdict(int)
for item in items:
if counts[item] < at_most:
counts[item] += 1
yield item
Note we can verify the equivalence via:
import random
motives = [random.randint(0, 100) for _ in range(1_000)]
print(list(delete_nth_v5(motives, 2)) == delete_nth_v4(motives, 2))
You code has few flaws, but the one you should never, ever do (unless you really know what is going on) is removing elements from lists (and other collections) while iterating over it
l = [1, 2, 3, 4, 5]
for el in l:
l.remove(el)
print(l) # it's not empty!
I suggest to iterate over list and count elements (with dict or Counter) while creating new list with elements that has no count bigger than max_e
def delete_nth(order, max_e):
c = Counter()
res = []
for el in order:
if c[el] < max_e:
c[el] += 1
res.append(el)
return res

What is in python, fastest way of reversing a part of a list in place?

Supopse I have the a huge list (say ten million elements) and I want to reverse all of the elements except last. The easiest aproach is:
a[0:-1] = a[-1::-1]
But the problem is that I think a temporary list is created. If it is so, how can avoid it?
[Edit]
For a more general case consider reversing a middle part of the list:
The only reason you may want to avoid copying the list is if you think it is too big for doing possible repeated copies.
I think there is no other way of doing it (without copies) than going manual:
a = [1, 2, 3, 4, 5, 6]
def revert_slice(first, last, a_list):
while first < last:
a_list[first], a_list[last] = a_list[last], a_list[first]
first += 1
last -= 1
revert_slice(0, 2, a)
print(a)
Outputs:
[3, 2, 1, 4, 5, 6]
In the call, only a temporary copy of the reference is made, not a list copy.
To achieve list reversal, except last item , i would just do -
>>> a=[1,2,3,4,5]
>>> temp=a.pop()
>>> a.reverse()
>>> a.append(temp)
>>> print(a)
[4, 3, 2, 1, 5]

How to reorder a python list backwards starting with the 0th element?

I'm trying to go through a list in reverse order, starting with the -0 indexed item (which is also the 0th item), rather than the -1 indexed item, so that I'll now have the new list to use. I've come up with two ways to do this, but neither seems both concise and clear.
a_list = [1, 2, 3, 4, 5]
print(a_list[:1] + a_list[:0:-1]) # take two slices of the list and add them
# [1, 5, 4, 3, 2]
list_range = range(-len(a_list)+1,1)[::-1] # create an appropriate new index range mapping
print([a_list[i] for i in list_range]) # list comprehension on the new range mapping
# [1, 5, 4, 3, 2]
Is there a way in python 3 to use slicing or another method to achieve this more simply?
If you are up for a programming golf:
>>> a_list = [1, 2, 3, 4, 5]
>>> [a_list[-i] for i in range(len(a_list))]
[1, 5, 4, 3, 2]
I think your first suggestion is the cleanest way of doing this. If you're really optimizing for character count, you can remove two characters from the first slice:
print(a_list[:1] + a_list[:0:-1])
Shift everything left by one and reverse.
my_list.append(my_list.pop(0))
print my_list[::-1]

python 'int' object has no attribute 'sort'

Hey I am new to Python and I have this exercise I want to complete but I get the following error: 'int' object has no attribute 'sort'.
I must use for-loop to take from a list of numbers and make them all square, then print them all out one by one as sorted.
Did I use the sort command incorrectly? Or it doesen't even work with numbers? And do I have to use the .append() command to make them all print out one by one?
So this is my wannabe code so far:
start_list = [5, 3, 1, 2, 4]
square_list = []
for square_list in start_list:
square_list ** 2
print square_list.sort()
There are three issues:
You're assigning from the start_list over your square_list in the for loop.
You're not appending your result into the list (this would fail anyway, because of the above).
The end result is that your square_list is not a list and so cannot be sorted.
Compare the following code:
start_list = [5, 3, 1, 2, 4]
square_list = []
for item in start_list:
square_list.append(item ** 2)
Here we iterate over the list taking an item for each loop. We then square it (using ** 2) and then append it to square_list.
There is also an issue in the print statement: print square_list.sort()
Here you are using .sort() on the list and then trying to print the returned value. But .sort() sorts the list in place and then returns None. So this line will always print None. To print the sorted list you can either use the sorted() function which returns the sorted list, ready to be passed to print:
print sorted(square_list)
Or you can sort the list before printing:
square_list.sort()
print square_list
The most pythonic solution is
start_list = [5, 3, 1, 2, 4]
square_list = [ i ** 2 for i in start_list ]
print(sorted(square_list))
or oneliner:
print(sorted(i ** 2 for i in [5, 3, 1, 2, 4]))
Let's dissect your code:
# here you create an empty list and assign it to
# square list
square_list = []
# yet here you will assign each item of start_list
# to the name square list one by one
for square_list in start_list:
# then you square that number, but it is not stored anywhere
square_list ** 2
# at this point, square_list contains the last element
# of start_list, that is the integer number 4. It does
# not, understandably, have the `.sort` method.
print square_list.sort()
The straightforward fix would be to do:
start_list = [ 5, 3, 1, 2, 4 ]
square_list = []
for element in start_list:
square_list.append(element ** 2)
square_list.sort() # note that printing this would say "None"
print square_list
You must understand for loops.
for square_list in start_list:
square_list ** 2
square_list in this example doesn't refer to the empty list you made. It is used as an ambiguous variable to extract values from a list. As such, this is just the each value in the list during each iteration, and they're all integers because that's what's in your list.
Secondly, you're not actually appending the squares to the list, you're just calculating the squares and doing nothing with them. Lastly, the sort method doesn't return anything, it just alters the list without returning a value. Use the equivalent sorted method which doesn't alter the list but does return a new value. I think you'll best understand with some code.
start_list = [5, 3, 1, 2, 4]
square_list = []
# for loop number is ambiguous variable
for number in start_list:
square = number ** 2 # calculate square to add later
square_list.append(square) # add the calculation
print sorted(square_list) # print sorted version
After loop your square_list is bound to integer [to be precise, it's value is 4].
To create list of squared numbers you may use list comprehensions:
square_list = [i**2 for i in start_list]
And then sort it:
square_list.sort()

Using for loop in Python 3.4 to remove particular element from array

As I am new to programming in Python. I am trying to remove particular elements from array using for loop which looks like
a=[2,3,1,4,1,1,1,5]
n=a.count(1)
for i in range (len(a)-n):
if (a[i]==1):
del a[i]
else:
a[i]=a[i]
print (a)
I want to remove 1 from array a. But, I am getting result as:
[2, 3, 4, 1, 1, 5].
That is 1 still exists in my new array. Can somebody please answer my problem?
try like this:
a = [2,3,1,4,1,1,1,5]
a = [x for x in a if x!=1] # this is called list comprehension
note Never modify list while iterating
Use a while loop and the remove method:
a = [2, 3, 1, 4, 1, 1, 1, 5]
while 1 in a:
a.remove(1)
print a
The real answer to your question (which none of the other answers addresses) is that every time you remove an item, the index i moves past it.
in your case:
a = [2,3,1,4,1,1,1,5]
after deleting the 5th item in the original list, the pointer moves to the 6th item, and the new 5th item (the second 1 in the sequence of three 1s) is skipped.
Regarding the comment never modify a list in a loop, try to implement an in-place algorithm like Fisher-Yates without modifying the list. Never say never. Know what you're doing.
The OP changes the list in-place, not creating a new list.
There are two methods, the second is safe, the first might be faster.
a = [2, 3, 1, 4, 1, 1, 1, 5]
toremove = 1
for i in range(len(a)-1, -1, -1):
if a[i] == toremove:
del a[i]
and
a = [2, 3, 1, 4, 1, 1, 1, 5]
toremove = 1
for i in range(a.count(toremove)):
a.remove(toremove)
The second removes the element however many times it exists (before the loop). Since we are not iterating on the list, it is safe to use the remove method.
Both fragments should be O(n) (but haven't done the calculations).
You can copy a and then remove but you cannot iterate over and delete elements from the same list, if your list starts with n elements python will have n pointers to each element so removing elements from the list as your are iterating over it will cause elements to be missed.python has no way of knowing you have removed elements from the list:
a = [2,3,1,4,1,1,1,5]
for ele in a[:]:
if ele == 1:
a.remove(1)
print(a)
[2, 3, 4, 5]
You can also use reversed which returns and iterator avoiding creating a whole copy of the list at once:
a = [2,3,1,4,1,1,1,5]
for ele in reversed(a):
if ele == 1:
a.remove(1)
print(a)
[2, 3, 4, 5]
Or using a list comprehension with the [:] syntax so we actually update the original object:
a[:] = (ele for ele in a if ele != 1)
All the above are linear operations using a single pass over a.
Actually as the del statement will remove elements from your list , and as the list that you bound in your loop doesn't been update after the first deleting you remove incorrect elements from your list , so if you want to use del you need to make the list name in your loop to reference to new list , that you can use a function for this aim , but as a more python way you can just use a list comprehension:
>>> a=[2,3,1,4,1,1,1,5]
>>> a=[i for i in a if i !=1]
>>> a
[2, 3, 4, 5]
Or you can use filter :
>>> a=[2,3,1,4,1,1,1,5]
>>> a=filter(lambda x: x !=1,a)
>>> a
[2, 3, 4, 5]

Categories