How do you make a list of lists within a for loop?
Here is what I have coded right now:
a = 0
xy=[[[],[]],[[],[]],[[],[]],[[],[]],[[],[]],[[],[]],[[],[]],[[],[]],[[],[]],[[],[]],[[],[]],[[],[]]]
for liness in range(len(NNCatelogue)):
a=0
for iii in range(len(NNCatelogue[liness])):
while a < len(catid):
if catid[a]==NNCatelogue[liness][iii]:
xyiii = (catid[a], a)
xy.append(xyiii)
a += 1
The output that I get is a lengthy list of pairs, as expected. It looks somewhat like the following:
[...,('C-18-1262', 30908),
('C-18-1264', 30910),
('C-18-1265', 30911),
('C-18-1267', 30913),
('C-18-1250', 30896),
('C-18-1254', 30900),...]
I would like to turn this list of pairs into a list of lists of pairs though. There are 1268 iterations, and the length of each list should be 12. (So 1268 lists with 12 elements in each of them). Any ideas for how to approach this when in a loop?
Something like this, perhaps. Note that I am using iteration over the lists directly to save a lot of unnecessary indexing.
xy = []
for line in NNCatelogue:
l = []
for c in line:
for a, ca in enumerate(catid):
if ca == c:
l.append((ca, a))
xy.append(l)
If you're using the inner loop just to search for the category index, as I suspect you are, a dictionary may be a useful addition to avoid the inner loop.
I have a few friendly suggestions right off the bat:
First of all, the a=0 at the very beginning is redundant. You do the
same thing twice with the a=0 inside of the first for loop.
Second, why are you declaring a huge framework of list elements for xy at
the top? You can always append() what you need as you go
along.
Finally, your while loop is just a simple for loop:
for n in range(len(catid)):
You can make a list of lists using list expansions like so:
list_of_lists = [[j for j in range(0, 3)] for _ in range(0, 3)]
Which outputs a 3x3 list:
[ [0, 1, 2],
[0, 1, 2],
[0, 1, 2]
]
Related
from my understanding shouldn't the print for X be the same on both? the answer i need is the one that comes from the list-comprehension, which is a new list where every element is -1 from the original list. But the for-loop one only gives 1 element, I also don't know how that element is calculated. Printing x just gives the last element of the list. I'm sure i'm doing something wrong but i'm not sure how to get a list from just using the for-loop. WHAT IS CONFUSING ME is that if the print(x) is part of the for loop it will print the elements of the desired list I need, but NOT in a list, which means the math I wrote works as intended, right?
list= [1,2,3,4,5]
#loop
x=[]
for i in list:
x=[i-1]
print(x)
#list comprehension
x=[i-1 for i in list]
print(x)
#confusing part where this print will be the same as the comprehension but not in a list form
x=[]
for i in list:
x=[i-1]
print(x)
First thing, list is a protected keyword. You should be using list_ at least (that's the naming convention if you really need to use list as the name).
The second iterates element by element, and prints each of the elements, what you want is in the loop to set each of the elements one by one, and then print x (not inside the loop).
list_= [1,2,3,4,5]
x=[]
for i in list_:
x.append(i-1)
print(x)
You should append like this:
lst= [1,2,3,4,5]
#loop
x=[]
for i in lst:
x.append(i-1)
print(x)
#output: [0, 1, 2, 3, 4]
#list comprehension
x=[i-1 for i in lst]
print(x)
#output: [0, 1, 2, 3, 4]
d = 3
cl = [1,3,4]
for i in cl:
if i <= d:
cl.remove(i)
print(cl)
output >> [3,4]
The number 3 should not be in the list as it passed the i <= d condition so cl.remove should've been called but it is in the output. What am I doing wrong here?
It happens because you're removing elements from list while iterating over it. It could be solved like this
[num for num in cl if num > d]
This works
d = 3
cl = [1, 3, 4]
for i in range(len(cl)):
if cl[i-1] <= d:
cl.remove(cl[i-1])
print(cl)
Please can you accept if it works...
This is the result of mutating a data structure during iteration. The for loop essentially creates an iterator over your list, with each item calling next(iterator). However, popping items off changes what the iterator is looking at
a = [1, 2, 3, 4]
it = iter(a)
# First iteration
next(it)
1
# remove element
a.pop(0)
1
# we skipped 2!
next(it)
3
Why? Well, we effectively changed what element the iterator is pointing to by removing the element we were currently on. We were looking at the first element in the sequence, but that was removed, so now the second element is the first one. So the call to next then points to the following element. This winds up looking like it was skipped when it wasn't, you just unintentionally had elements shuffled forward.
To avoid this, it's best to create a new list by filtering, as #AlexanderLekontsev suggests in his answer. This avoids mutating while iterating. You can do this with a standard loop with append like so:
newlist = []
for num in cl:
if num >= d:
newlist.append(num)
Essentially, because you are removing elements from the list while iterating over it, you have skipped over the value 3.
In the first iteration of your for-loop, you remove the value 1. Because of how iterations work in Python, in your second iteration of the for-loop, you are looking for next(next(cl)). But, cl has been updated to [3,4], since you removed 1. So now next(next(cl)) = next(3) = 4 and so you've skipped over 3.
You can resolve this by creating a new list and updating it as you go along. An easy way to do this using list comprehension is simply [num for num in cl if num > d].
Given a list of integers, I want to check a second list and remove from the first only those which can not be made from the sum of two numbers from the second. So given a = [3,19,20] and b = [1,2,17], I'd want [3,19].
Seems like a a cinch with two nested loops - except that I've gotten stuck with break and continue commands.
Here's what I have:
def myFunction(list_a, list_b):
for i in list_a:
for a in list_b:
for b in list_b:
if a + b == i:
break
else:
continue
break
else:
continue
list_a.remove(i)
return list_a
I know what I need to do, just the syntax seems unnecessarily confusing. Can someone show me an easier way? TIA!
You can do like this,
In [13]: from itertools import combinations
In [15]: [item for item in a if item in [sum(i) for i in combinations(b,2)]]
Out[15]: [3, 19]
combinations will give all possible combinations in b and get the list of sum. And just check the value is present in a
Edit
If you don't want to use the itertools wrote a function for it. Like this,
def comb(s):
for i, v1 in enumerate(s):
for j in range(i+1, len(s)):
yield [v1, s[j]]
result = [item for item in a if item in [sum(i) for i in comb(b)]]
Comments on code:
It's very dangerous to delete elements from a list while iterating over it. Perhaps you could append items you want to keep to a new list, and return that.
Your current algorithm is O(nm^2), where n is the size of list_a, and m is the size of list_b. This is pretty inefficient, but a good start to the problem.
Thee's also a lot of unnecessary continue and break statements, which can lead to complicated code that is hard to debug.
You also put everything into one function. If you split up each task into different functions, such as dedicating one function to finding pairs, and one for checking each item in list_a against list_b. This is a way of splitting problems into smaller problems, and using them to solve the bigger problem.
Overall I think your function is doing too much, and the logic could be condensed into much simpler code by breaking down the problem.
Another approach:
Since I found this task interesting, I decided to try it myself. My outlined approach is illustrated below.
1. You can first check if a list has a pair of a given sum in O(n) time using hashing:
def check_pairs(lst, sums):
lookup = set()
for x in lst:
current = sums - x
if current in lookup:
return True
lookup.add(x)
return False
2. Then you could use this function to check if any any pair in list_b is equal to the sum of numbers iterated in list_a:
def remove_first_sum(list_a, list_b):
new_list_a = []
for x in list_a:
check = check_pairs(list_b, x)
if check:
new_list_a.append(x)
return new_list_a
Which keeps numbers in list_a that contribute to a sum of two numbers in list_b.
3. The above can also be written with a list comprehension:
def remove_first_sum(list_a, list_b):
return [x for x in list_a if check_pairs(list_b, x)]
Both of which works as follows:
>>> remove_first_sum([3,19,20], [1,2,17])
[3, 19]
>>> remove_first_sum([3,19,20,18], [1,2,17])
[3, 19, 18]
>>> remove_first_sum([1,2,5,6],[2,3,4])
[5, 6]
Note: Overall the algorithm above is O(n) time complexity, which doesn't require anything too complicated. However, this also leads to O(n) extra auxiliary space, because a set is kept to record what items have been seen.
You can do it by first creating all possible sum combinations, then filtering out elements which don't belong to that combination list
Define the input lists
>>> a = [3,19,20]
>>> b = [1,2,17]
Next we will define all possible combinations of sum of two elements
>>> y = [i+j for k,j in enumerate(b) for i in b[k+1:]]
Next we will apply a function to every element of list a and check if it is present in above calculated list. map function can be use with an if/else clause. map will yield None in case of else clause is successful. To cater for this we can filter the list to remove None values
>>> list(filter(None, map(lambda x: x if x in y else None,a)))
The above operation will output:
>>> [3,19]
You can also write a one-line by combining all these lines into one, but I don't recommend this.
you can try something like that:
a = [3,19,20]
b= [1,2,17,5]
n_m_s=[]
data=[n_m_s.append(i+j) for i in b for j in b if i+j in a]
print(set(n_m_s))
print("after remove")
final_data=[]
for j,i in enumerate(a):
if i not in n_m_s:
final_data.append(i)
print(final_data)
output:
{19, 3}
after remove
[20]
I have tried this, it gives the output it should give([1,3,2]), however the problem is it keeps printing the output for infinite times without stop,, is there any solutions with out changing the idea of the code.
a= [1,2,2,2,1,3,2]
def rem_dup(L):
while len(L):
for i in L:
y= L.count(i)
if y>1:
L.remove(i)
print L
rem_dup(a)
Unless the point of this function is to exercise your python skills, it sounds like you want a set. A set is like a list but does not allow duplicate values. If you want your final data structure to be a list, you could do something like this:
final_list = list(set(original_list))
One way to safely do this is to loop over the list in reverse and remove only from the back:
>>> for i in range(len(a) - 1, -1, -1):
... if a.count(a[i]) > 1:
... del a[i]
...
>>> a
[1, 2, 3]
But this will be polynomial time, since a.count is linear and so is del a[i].
while len(L) will always be true as long as L had something in it to begin with
Modifying L while using it with the for loop can cause items to be skipped, so you have a bug for some inputs.
If you fix that problem, you shouldn't need the while loop.
As long as the items in a are hashable and you don't mind that the remaining items aren't in the same order when you started, you can create an intermediate set and replace the original contents in-place.
a[:] = set(a)
How can I rewrite this using nested for loops instead of a list comprehension?
final= [[]]
for i in array_list:
final.extend([sublist + [i] for sublist in final])
return final
If you try to iterate over final as you extend it, it creates an infinite loop. Because every time you go to the next element, you add another element, so you never reach the end of the list.
If you want to do the inner loop as a for loop instead of a list comprehension, you need to iterate over a copy of final.
final = [[]]
for i in [1, 2, 3]:
for sublist in final[:]:
final.extend([sublist + [i]])
Your solution looks to be a very good for loop one. A one-liner using itertools is possible, but ugly
list(itertools.chain(list(itertools.combinations(arr, i)) for i in range(len(arr) + 1)))
EDIT:
Prettier:
list(itertools.chain(*[itertools.combinations(arr, i) for i in range(len(arr)+1)]))
This code also seems to give the same results as your code.
final = [[]]
for i in array_list:
for sublist in list(final):
final.extend([sublist + [i]])
return final
It seems like your code takes the elements of the last iteration and combines them with the element of the current iteration (See 'Example' below). In order to do this with a traditional for loop, you need to prevent the list that is being looped over from being updated while looping. I do this by breaking the link with the 'final' list variable. This can be done with the list() function or by slicing it (then you would need to replace with as proposed by Morgan).
Example
For the array_list of [1,2,3] you get the following. Each line (except for the lines) is a new element of the 'final' list variable.
[]
--------------------------------
1 > array_list[0]
--------------------------------
2 > array_list[1]
1, 2 > array_list[0] + array_list[1]
--------------------------------
3 > array_list[2]
1, 3 > array_list[0] + array_list[2]
2, 3 > array_list[1] + array_list[2]
1, 2, 3 > array_list[0] + array_list[1] + array_list[2]