Ok so I'm trying to solve this logical question in a pythonic way, but I'm not very good. Here goes:
You have a piece of paper with a list of numbers on it like so:
1 2 3 4 | 5 6 7 8
If you fold the paper from the left to the right down the middle, you get this order:
(first number is on top)
(4,5) (3,6) (2,7) (1,8)
And you can fold it one more time either way, and get a new order (right-to-left example):
(first number on top, then second below, ...etc)
(8,1,4,5) (7,2,3,6)
I started with seeing how to fold the paper and get a list of lists with the correct order:
paper = [1, 2, 3, 4, 5, 6, 7, 8]
half_paper = len(paper)/2
s = paper[:half_paper]
e = paper[half_paper:]
middle_distance = 0
final_list = []
for l in range(half_paper):
print l
m = [s[half_paper-middle_distance-1],e[middle_distance-half_paper]]
final_list.append(m)
middle_distance += 1
print final_list
This works, results in [[4,5], [3,6], [2,7], [1,8]] (fold left to right). But now I'm stuck. I've been trying to figure out a way to use list comprehension to apply the logic on the final_list result, so I can "fold" the paper again to get a result of [[5,4,1,8], [6,3,2,7]] (fold left to right again, or if fold right to left [[8,1,4,5], [7,2,3,6]]).
I'm not sure how to use list comprehension to do what i did in the for loop, on a list of lists and result in a list of lists. Any ideas to get me started?
l = [1, 2, 3, 4, 5, 6, 7, 8]
l1,l2 = l[:len(l)/2], l[len(l)/2:]
l = [ [x,y] for x,y in zip (l1, l2[::-1])]
for i in range(len(l)):
if isinstance(l[i][0], list):
l[i] = [x for item in l[i] for x in item]
print l
l1,l2 = l[:len(l)/2], l[len(l)/2:]
l = [ [x,y] for x,y in zip (l1, l2[::-1])]
for i in range(len(l)):
if isinstance(l[i][0], list):
l[i] = [x for item in l[i] for x in item]
print l
Output
[[1, 8], [2, 7], [3, 6], [4, 5]]
[[1, 8, 4, 5], [2, 7, 3, 6]]
Related
I have a list and would like to convert all duplicates values to 3 without changing the order and without importing any packages
X = [1, 2, 2, 5, 4, 8, 6]
Desired output:
X = [1, 3, 3, 5, 4, 8, 6]
This code automatically replace all duplicate items with 3
my_list = [1, 2, 2, 5, 4, 8, 6]
new = []
for item in my_list:
if my_list.count(item) > 1:
new.append(3)
else:
new.append(item)
print(new)
Among the fastest
fr = {x:0 for x in X}
for n in X:
fr[n] += 1
Y = [3 if fr[n]>1 else n for n in X]
You iterate over the list and add one to the dictionary counter for that number.
Then you create a list with list comprehension: you change the value to 3 if it is repeated more than once.
Little bit slower and little bit shorter
xi = {x:i for i, x in enumerate(X)}
dp = {x: xi[x]>i for i, x in reversed(list(enumerate(X)))}
Y = [3 if dp[x] else x for x in X]
You iterate over X and keep the lastest index of each value. Then you iterate again but in reverse order, and ask if there is another index for that value. Then with that info you create the desired output. All using list/dict comprehension. This is more of a functional approach.
Not sure why another user deleted their answer but that was a pretty simple one and uses basic list comprehension. So I am bringing the same to you. Please refer the code below for same:
X = [1, 2, 2, 5, 4, 8, 6]
print([3 if e==2 else e for e in X])
You should be able to use a for loop for this
my_list = [1, 2, 2, 5, 4, 8, 6]
new_list = []
for i in range(len(my_list)):
if my_list[i] in new_list:
new_list.append(3)
else:
new_list.append(my_list[i])
print(new_list)
Output:
[1, 3, 3, 5, 4, 8, 6]
Maybe something like this:
X = [t if t not in X[:i] + X[i+1:] else 3 for i, t in enumerate(X)]
I want to remove duplicate items from lists in sublists on Python.
Exemple :
myList = [[1,2,3], [4,5,6,3], [7,8,9], [0,2,4]]
to
myList = [[1,2,3], [4,5,6], [7,8,9], [0]]
I tried with this code :
myList = [[1,2,3],[4,5,6,3],[7,8,9], [0,2,4]]
nbr = []
for x in myList:
for i in x:
if i not in nbr:
nbr.append(i)
else:
x.remove(i)
But some duplicate items are not deleted.
Like this : [[1, 2, 3], [4, 5, 6], [7, 8, 9], [0, 4]]
I still have the number 4 that repeats.
You iterate over a list that you are also modifying:
...
for i in x:
...
x.remove(i)
That means that it may skip an element on next iteration.
The solution is to create a shallow copy of the list and iterate over that while modifying the original list:
...
for i in x.copy():
...
x.remove(i)
You can make this much faster by:
Using a set for repeated membership testing instead of a list, and
Rebuilding each sublist rather than repeatedly calling list.remove() (a linear-time operation, each time) in a loop.
seen = set()
for i, sublist in enumerate(myList):
new_list = []
for x in sublist:
if x not in seen:
seen.add(x)
new_list.append(x)
myList[i] = new_list
>>> print(myList)
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [0]]
If you want mild speed gains and moderate readability loss, you can also write this as:
seen = set()
for i, sublist in enumerate(myList):
myList[i] = [x for x in sublist if not (x in seen or seen.add(x))]
Why you got wrong answer: In your code, after scanning the first 3 sublists, nbr = [1, 2, 3, 4, 5, 6, 7, 8, 9]. Now x = [0, 2, 4]. Duplicate is detected when i = x[1], so x = [0, 4]. Now i move to x[2] which stops the for loop.
Optimization has been proposed in other answers. Generally, 'list' is only good for retrieving element and appending/removing at the rear.
NOTE: My need isn't this e.g. List[2:4] = 5
Suppose my List=[1,2,3,4,5,6]
I want to add 5 from index 2 to 4.
So the resultant List would be like List=[1,2,8,9,10,6]
If I have 2d array List=[[1,2,3],[4,5,6]] and want to add 5 to col 1 List=[[6,2,3],[9,5,6]]then what would be the code?
One approach is
my_list = [1,2,3,4,5]
add_item = [2,3]
new_list = [x+1 if i in add_item else x for i, x in enumerate(my_list)]
print(new_list)
This can be easily done through list comprehension.
The following function takes a 2D array 2d, a position index i and a value v, and adds v to the i-th element of each array.
def add_value(2d, i, v):
return [array[:i] + [array[i]+v] + array[i+1:] for array in 2d]
So, calling the function on the list in your example:
my_list = [[1,2,3],[4,5,6]]
add_value(my_list,0,5)
Would print out the desired output:
>>> [[6, 2, 3], [9, 5, 6]]
Numpy arrays can handle such slice operations:
import numpy as np
List = np.array([1, 2, 3, 4, 5, 6])
List[2:5] += 5
print(List)
Numpy will really come in handy for you if you have many of such tasks to do in your code. However, if it's just a one time thing in your code, you can do:
List = [1, 2, 3, 4, 5, 6]
for i in range(2, 5):
List[i] += 5
print(List)
Output:
[1, 2, 8, 9, 10, 6]
EDIT
Addressing your edit, you can also use numpy arrays like so:
import numpy as np
List = np.array([[1, 2, 3], [4, 5, 6]])
List[0] += 5
print(List)
Or using a loop:
List = [[1, 2, 3], [4, 5, 6]]
for i in range(len(List[0])):
List[0][i] += 5
print(List)
Output:
[[6, 7, 8], [4, 5, 6]]
One solution uses NumPy but my implementation is on an in-built list and other solutions are copying unnecessary elements.
So here I found the manual way to do it.
List = [[1,2,3,4,5],[6,7,8,9,10]]
# for horizontal update
colToUpdate = 2
for r in range(0,2):
A[r][colToUpdate] += add
# for vertical update
rowToUpdate = 1
for c in range(2,5):
A[rowToUpdate][c] += add
There are many solution available on internet for the above question but i am building my own logic here and have written below solution so far but my code is not dynamic e.g my code is only working for num = 2.
How can we write code for dynamic user input using below logic. Any suggestion will be appreciated.
My Code:
l = [1,2,3,4,5,6,7]
l1 = []
num = 2
print('original list is:', l)
for i in range(0,num-1):
rem = l.pop(i)
l1.append(rem)
for i in range(0,num-1):
rem = l.pop(i)
l1.append(rem)
print('poup list is',l1)
l.extend(l1)
print('reverse list is',l)
My Output: (when num = 2)
original list is: [1, 2, 3, 4, 5, 6, 7]
poup list is [1, 2]
reverse list is [3, 4, 5, 6, 7, 1, 2]
My Output: (when num = 3)
original list is: [1, 2, 3, 4, 5, 6, 7]
poup list is [1, 3, 2, 5]
reverse list is [4, 6, 7, 1, 3, 2, 5]
Expected Solution:
l = [1,2,3,4,5,6,7]
num = 2 (This number can be dynamic, User can pass any number)
Output: l = [3,4,5,6,7,1,2]
If user passed num = 3 then output should be like below:
Output: l = [4,5,6,7,1,2,3]
Even though the poup list and reverse list doesn't seem to represent the lists with the best names, the following code snippet should solve your problem:
l = [1,2,3,4,5,6,7]
print("Original list: {}".format(l) )
num = input("Enter value of 'num': " )
l1 = []
for i in range(0,int(num)):
rem = l.pop(0)
l1.append(rem)
print('poup list is',l1)
l.extend(l1)
print('reverse list is',l)
Here num is dynamically stored. The only minor correction to your for loop is that l should always pop the first element. This is because once an element is popped, the second element becomes the first element of your list. But due to incrementation in the value of i, it just skips that element.
Here's a sample output:
Original list: [1, 2, 3, 4, 5, 6, 7]
Enter value of 'num': 4
poup list is [1, 2, 3, 4]
reverse list is [5, 6, 7, 1, 2, 3, 4]
You could use a while loop. Problem with your code is that index positions changed when popping, in case of num = 2 it was fine, but then it messed up with new positions.
l = [1,2,3,4,5,6,7]
l1 = []
num = 3
print('original list is:', l)
y = 0
while y != num:
rem = l.pop(0)
y +=1
l1.append(rem)
print(l)
print('poup list is',l1)
l.extend(l1)
print('reverse list is',l)
I have two lists that i need to combine where the second list has any duplicates of the first list ignored. .. A bit hard to explain, so let me show an example of what the code looks like, and what i want as a result.
first_list = [1, 2, 2, 5]
second_list = [2, 5, 7, 9]
# The result of combining the two lists should result in this list:
resulting_list = [1, 2, 2, 5, 7, 9]
You'll notice that the result has the first list, including its two "2" values, but the fact that second_list also has an additional 2 and 5 value is not added to the first list.
Normally for something like this i would use sets, but a set on first_list would purge the duplicate values it already has. So i'm simply wondering what the best/fastest way to achieve this desired combination.
Thanks.
You need to append to the first list those elements of the second list that aren't in the first - sets are the easiest way of determining which elements they are, like this:
first_list = [1, 2, 2, 5]
second_list = [2, 5, 7, 9]
in_first = set(first_list)
in_second = set(second_list)
in_second_but_not_in_first = in_second - in_first
result = first_list + list(in_second_but_not_in_first)
print(result) # Prints [1, 2, 2, 5, 9, 7]
Or if you prefer one-liners 8-)
print(first_list + list(set(second_list) - set(first_list)))
resulting_list = list(first_list)
resulting_list.extend(x for x in second_list if x not in resulting_list)
You can use sets:
first_list = [1, 2, 2, 5]
second_list = [2, 5, 7, 9]
resultList= list(set(first_list) | set(second_list))
print(resultList)
# Results in : resultList = [1,2,5,7,9]
first_list = [1, 2, 2, 5]
second_list = [2, 5, 7, 9]
print( set( first_list + second_list ) )
You can bring this down to one single line of code if you use numpy:
a = [1,2,3,4,5,6,7]
b = [2,4,7,8,9,10,11,12]
sorted(np.unique(a+b))
>>> [1,2,3,4,5,6,7,8,9,10,11,12]
Simplest to me is:
first_list = [1, 2, 2, 5]
second_list = [2, 5, 7, 9]
merged_list = list(set(first_list+second_list))
print(merged_list)
#prints [1, 2, 5, 7, 9]
resulting_list = first_list + [i for i in second_list if i not in first_list]
You can also combine RichieHindle's and Ned Batchelder's responses for an average-case O(m+n) algorithm that preserves order:
first_list = [1, 2, 2, 5]
second_list = [2, 5, 7, 9]
fs = set(first_list)
resulting_list = first_list + [x for x in second_list if x not in fs]
assert(resulting_list == [1, 2, 2, 5, 7, 9])
Note that x in s has a worst-case complexity of O(m), so the worst-case complexity of this code is still O(m*n).
Based on the recipe :
resulting_list = list(set().union(first_list, second_list))
you can use dict.fromkeys to return a list with no duplicates:
def mergeTwoListNoDuplicates(list1, list2):
"""
Merges two lists together without duplicates
:param list1:
:param list2:
:return:
"""
merged_list = list1 + list2
merged_list = list(dict.fromkeys(merged_list))
return merged_list
This might help
def union(a,b):
for e in b:
if e not in a:
a.append(e)
The union function merges the second list into first, with out duplicating an element of a, if it's already in a. Similar to set union operator. This function does not change b. If a=[1,2,3] b=[2,3,4]. After union(a,b) makes a=[1,2,3,4] and b=[2,3,4]
first_list = [1, 2, 2, 5]
second_list = [2, 5, 7, 9]
newList=[]
for i in first_list:
newList.append(i)
for z in second_list:
if z not in newList:
newList.append(z)
newList.sort()
print newList
[1, 2, 2, 5, 7, 9]