Building a list inside a list in python - python

I have been trying to add some data in a python list. I am actually going to store the data as a list inside a list. Now, the data is not coming index-wise.
To explain that lets say I have a list of lists 'a'. Now I have data for a[2] before a[1]. And both a[1] and a[2] are lists themselves. Now, obviously I can't assign anything to a[2] before assigning a[1]. And I don't know how much lists would be there. I mean, this is supposed to be dynamic.
Any solution to this, so that I can successfully build the list?

You could append empty lists until you have enough to access the index you have data for:
while len(outerlist) <= idx:
outerlist.append([])
However, you may want to use a dictionary instead, letting you implement a sparse object instead. A collections.defaultdict() object is especially useful here:
from collections import defaultdict
data = defaultdict(list)
data[2].append(3)
data[5].append(42)
data now has keys 2 and 5, each a list with one element. No entries for 0, 1, 3, or 4 exist yet.

I had the same problem, to fill empty list with definite amount of lists.
Here is my way out
I made a "board" 6x6 filled with O, just for instant:
board = []
for i in range(6): # create a list with nested lists
board.append([])
for n in range(6):
board[i].append("O") # fills nested lists with data
Result:
[['O', 'O', 'O', 'O', 'O', 'O'],
['O', 'O', 'O', 'O', 'O', 'O'],
['O', 'O', 'O', 'O', 'O', 'O'],
['O', 'O', 'O', 'O', 'O', 'O'],
['O', 'O', 'O', 'O', 'O', 'O'],
['O', 'O', 'O', 'O', 'O', 'O']]

I think this solution solves your problem.
Create the secondary list(inside_list) local to the for loop
outside_list=[]
for i in range(0,5):
inside_list=[]
inside_list.append(i)
inside_list.append(i+1)
outside_list.append(inside_list)
#you can access any inside_list from the outside_list and append
outside_list[1].append(100)
print(outside_list)
Output:
[[0, 1], [1, 2, 100], [2, 3], [3, 4], [4, 5]]

You can do it, there is no problem appending an element.
>>> a = [[1,2,3], [10,20,30], [100,200,300]]
>>> a[2].append(400)
[[1, 2, 3], [10, 20, 30], [100, 200, 300, 400]]
>>> a[1].append(40)
[[1, 2, 3], [10, 20, 30, 40], [100, 200, 300, 400]]

We can use the first item in the list as an index and then make use of it for adding the right value to it at runtime using the list.
def unclean_(index, val, unclean=None):
is_added = False
if unclean is None:
unclean = []
length = len(unclean)
if length == 0:
unclean.append([index, val])
else:
for x in range(length):
if unclean[x][0] == index:
unclean[x].append(val)
is_added = True
if not is_added:
unclean.append([index, val])
def terminate_even(x):
if x % 2 == 0:
raise Exception("Its even number")
def terminate_odd(x):
if x % 2 != 0:
raise Exception("Its odd number")
def fun():
unclean = []
for x in range(10):
try:
terminate_even(x)
except:
unclean_("terminate_even", x, unclean)
for x in range(10):
try:
terminate_odd(x)
except:
unclean_("terminate_odd", x, unclean)
for y in unclean:
print y
def main():
fun()
if __name__ == "__main__":
main()
Output:
-------
['terminate_even', 0, 2, 4, 6, 8]
['terminate_odd', 1, 3, 5, 7, 9]

Simply
I am gonna make it as simple as it gets, No need for fancy modules,
Just make an empty list in the start of the file, and then append that empty list whenever you need it like,
Example
Until the Function get_data give a certain output add empty lists within a list.
#/usr/bin/python3
#coding:utf-8
empty_list = []
r = ''
def get_data():
# does something here and gives the output
return output
imp_list = []
while r == %something%:
r = get_data()
imp_list.append(empty_list)

Related

How to merge two lists by alternating elements from both lists? [duplicate]

I have two lists, the first of which is guaranteed to contain exactly one more item than the second. I would like to know the most Pythonic way to create a new list whose even-index values come from the first list and whose odd-index values come from the second list.
# example inputs
list1 = ['f', 'o', 'o']
list2 = ['hello', 'world']
# desired output
['f', 'hello', 'o', 'world', 'o']
This works, but isn't pretty:
list3 = []
while True:
try:
list3.append(list1.pop(0))
list3.append(list2.pop(0))
except IndexError:
break
How else can this be achieved? What's the most Pythonic approach?
If you need to handle lists of mismatched length (e.g. the second list is longer, or the first has more than one element more than the second), some solutions here will work while others will require adjustment. For more specific answers, see How to interleave two lists of different length? to leave the excess elements at the end, or How to elegantly interleave two lists of uneven length in python? to try to intersperse elements evenly.
Here's one way to do it by slicing:
>>> list1 = ['f', 'o', 'o']
>>> list2 = ['hello', 'world']
>>> result = [None]*(len(list1)+len(list2))
>>> result[::2] = list1
>>> result[1::2] = list2
>>> result
['f', 'hello', 'o', 'world', 'o']
There's a recipe for this in the itertools documentation (note: for Python 3):
from itertools import cycle, islice
def roundrobin(*iterables):
"roundrobin('ABC', 'D', 'EF') --> A D E B F C"
# Recipe credited to George Sakkis
num_active = len(iterables)
nexts = cycle(iter(it).__next__ for it in iterables)
while num_active:
try:
for next in nexts:
yield next()
except StopIteration:
# Remove the iterator we just exhausted from the cycle.
num_active -= 1
nexts = cycle(islice(nexts, num_active))
import itertools
print([x for x in itertools.chain.from_iterable(itertools.zip_longest(list1,list2)) if x])
I think this is the most pythonic way of doing it.
In Python 2, this should do what you want:
>>> iters = [iter(list1), iter(list2)]
>>> print list(it.next() for it in itertools.cycle(iters))
['f', 'hello', 'o', 'world', 'o']
Without itertools and assuming l1 is 1 item longer than l2:
>>> sum(zip(l1, l2+[0]), ())[:-1]
('f', 'hello', 'o', 'world', 'o')
In python 2, using itertools and assuming that lists don't contain None:
>>> filter(None, sum(itertools.izip_longest(l1, l2), ()))
('f', 'hello', 'o', 'world', 'o')
If both lists have equal length, you can do:
[x for y in zip(list1, list2) for x in y]
As the first list has one more element, you can add it post hoc:
[x for y in zip(list1, list2) for x in y] + [list1[-1]]
To illustrate what is happening in that first list comprehension, this is how you would spell it out as a nested for loop:
result = []
for y in zip(list1, list2): # y is is a 2-tuple, containining one element from each list
for x in y: # iterate over the 2-tuple:
result.append(x)
I know the questions asks about two lists with one having one item more than the other, but I figured I would put this for others who may find this question.
Here is Duncan's solution adapted to work with two lists of different sizes.
list1 = ['f', 'o', 'o', 'b', 'a', 'r']
list2 = ['hello', 'world']
num = min(len(list1), len(list2))
result = [None]*(num*2)
result[::2] = list1[:num]
result[1::2] = list2[:num]
result.extend(list1[num:])
result.extend(list2[num:])
result
This outputs:
['f', 'hello', 'o', 'world', 'o', 'b', 'a', 'r']
Here's a one liner that does it:
list3 = [ item for pair in zip(list1, list2 + [0]) for item in pair][:-1]
Here's a one liner using list comprehensions, w/o other libraries:
list3 = [sub[i] for i in range(len(list2)) for sub in [list1, list2]] + [list1[-1]]
Here is another approach, if you allow alteration of your initial list1 by side effect:
[list1.insert((i+1)*2-1, list2[i]) for i in range(len(list2))]
This one is based on Carlos Valiente's contribution above
with an option to alternate groups of multiple items and make sure that all items are present in the output :
A=["a","b","c","d"]
B=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
def cyclemix(xs, ys, n=1):
for p in range(0,int((len(ys)+len(xs))/n)):
for g in range(0,min(len(ys),n)):
yield ys[0]
ys.append(ys.pop(0))
for g in range(0,min(len(xs),n)):
yield xs[0]
xs.append(xs.pop(0))
print [x for x in cyclemix(A, B, 3)]
This will interlace lists A and B by groups of 3 values each:
['a', 'b', 'c', 1, 2, 3, 'd', 'a', 'b', 4, 5, 6, 'c', 'd', 'a', 7, 8, 9, 'b', 'c', 'd', 10, 11, 12, 'a', 'b', 'c', 13, 14, 15]
Might be a bit late buy yet another python one-liner. This works when the two lists have equal or unequal size. One thing worth nothing is it will modify a and b. If it's an issue, you need to use other solutions.
a = ['f', 'o', 'o']
b = ['hello', 'world']
sum([[a.pop(0), b.pop(0)] for i in range(min(len(a), len(b)))],[])+a+b
['f', 'hello', 'o', 'world', 'o']
from itertools import chain
list(chain(*zip('abc', 'def'))) # Note: this only works for lists of equal length
['a', 'd', 'b', 'e', 'c', 'f']
itertools.zip_longest returns an iterator of tuple pairs with any missing elements in one list replaced with fillvalue=None (passing fillvalue=object lets you use None as a value). If you flatten these pairs, then filter fillvalue in a list comprehension, this gives:
>>> from itertools import zip_longest
>>> def merge(a, b):
... return [
... x for y in zip_longest(a, b, fillvalue=object)
... for x in y if x is not object
... ]
...
>>> merge("abc", "defgh")
['a', 'd', 'b', 'e', 'c', 'f', 'g', 'h']
>>> merge([0, 1, 2], [4])
[0, 4, 1, 2]
>>> merge([0, 1, 2], [4, 5, 6, 7, 8])
[0, 4, 1, 5, 2, 6, 7, 8]
Generalized to arbitrary iterables:
>>> def merge(*its):
... return [
... x for y in zip_longest(*its, fillvalue=object)
... for x in y if x is not object
... ]
...
>>> merge("abc", "lmn1234", "xyz9", [None])
['a', 'l', 'x', None, 'b', 'm', 'y', 'c', 'n', 'z', '1', '9', '2', '3', '4']
>>> merge(*["abc", "x"]) # unpack an iterable
['a', 'x', 'b', 'c']
Finally, you may want to return a generator rather than a list comprehension:
>>> def merge(*its):
... return (
... x for y in zip_longest(*its, fillvalue=object)
... for x in y if x is not object
... )
...
>>> merge([1], [], [2, 3, 4])
<generator object merge.<locals>.<genexpr> at 0x000001996B466740>
>>> next(merge([1], [], [2, 3, 4]))
1
>>> list(merge([1], [], [2, 3, 4]))
[1, 2, 3, 4]
If you're OK with other packages, you can try more_itertools.roundrobin:
>>> list(roundrobin('ABC', 'D', 'EF'))
['A', 'D', 'E', 'B', 'F', 'C']
My take:
a = "hlowrd"
b = "el ol"
def func(xs, ys):
ys = iter(ys)
for x in xs:
yield x
yield ys.next()
print [x for x in func(a, b)]
def combine(list1, list2):
lst = []
len1 = len(list1)
len2 = len(list2)
for index in range( max(len1, len2) ):
if index+1 <= len1:
lst += [list1[index]]
if index+1 <= len2:
lst += [list2[index]]
return lst
How about numpy? It works with strings as well:
import numpy as np
np.array([[a,b] for a,b in zip([1,2,3],[2,3,4,5,6])]).ravel()
Result:
array([1, 2, 2, 3, 3, 4])
Stops on the shortest:
def interlace(*iters, next = next) -> collections.Iterable:
"""
interlace(i1, i2, ..., in) -> (
i1-0, i2-0, ..., in-0,
i1-1, i2-1, ..., in-1,
.
.
.
i1-n, i2-n, ..., in-n,
)
"""
return map(next, cycle([iter(x) for x in iters]))
Sure, resolving the next/__next__ method may be faster.
Multiple one-liners inspired by answers to another question:
import itertools
list(itertools.chain.from_iterable(itertools.izip_longest(list1, list2, fillvalue=object)))[:-1]
[i for l in itertools.izip_longest(list1, list2, fillvalue=object) for i in l if i is not object]
[item for sublist in map(None, list1, list2) for item in sublist][:-1]
An alternative in a functional & immutable way (Python 3):
from itertools import zip_longest
from functools import reduce
reduce(lambda lst, zipped: [*lst, *zipped] if zipped[1] != None else [*lst, zipped[0]], zip_longest(list1, list2),[])
using for loop also we can achive this easily:
list1 = ['f', 'o', 'o']
list2 = ['hello', 'world']
list3 = []
for i in range(len(list1)):
#print(list3)
list3.append(list1[i])
if i < len(list2):
list3.append(list2[i])
print(list3)
output :
['f', 'hello', 'o', 'world', 'o']
Further by using list comprehension this can be reduced. But for understanding this loop can be used.
My approach looks as follows:
from itertools import chain, zip_longest
def intersperse(*iterators):
# A random object not occurring in the iterators
filler = object()
r = (x for x in chain.from_iterable(zip_longest(*iterators, fillvalue=filler)) if x is not filler)
return r
list1 = ['f', 'o', 'o']
list2 = ['hello', 'world']
print(list(intersperse(list1, list2)))
It works for an arbitrary number of iterators and yields an iterator, so I applied list() in the print line.
def alternate_elements(small_list, big_list):
mew = []
count = 0
for i in range(len(small_list)):
mew.append(small_list[i])
mew.append(big_list[i])
count +=1
return mew+big_list[count:]
if len(l2)>len(l1):
res = alternate_elements(l1,l2)
else:
res = alternate_elements(l2,l1)
print(res)
Here we swap lists based on size and perform, can someone provide better solution with time complexity O(len(l1)+len(l2))
I'd do the simple:
chain.from_iterable( izip( list1, list2 ) )
It'll come up with an iterator without creating any additional storage needs.
This is nasty but works no matter the size of the lists:
list3 = [
element for element in
list(itertools.chain.from_iterable([
val for val in itertools.izip_longest(list1, list2)
]))
if element != None
]
Obviously late to the party, but here's a concise one for equal-length lists:
output = [e for sub in zip(list1,list2) for e in sub]
It generalizes for an arbitrary number of equal-length lists, too:
output = [e for sub in zip(list1,list2,list3) for e in sub]
etc.
I'm too old to be down with list comprehensions, so:
import operator
list3 = reduce(operator.add, zip(list1, list2))

Check if list is valid sequence of chunks

I want to check whether a list is a valid sequence of chunks, where each chunk begins with some value and ends with the next occurrence of the same value. For example, this is a valid sequence of three chunks:
lst = [2, 7, 1, 8, 2, 8, 1, 8, 2, 8, 4, 5, 9, 0, 4, 5, 2]
\___________/ \_____/ \_______________________/
And this is one is invalid:
lst = [2, 7, 1, 8, 2, 8, 1, 8, 2, 8, 4, 5, 9, 0, 4]
\___________/ \_____/ \_____ ... missing the 2 to end the chunk
I have a solution but it's bad. Do you see something better?
def is_valid(lst):
while lst:
start = lst.pop(0)
if start not in lst:
return False
while lst[0] != start:
lst.pop(0)
lst.remove(start)
return True
# Tests, should print: True, False, True, False, True
print(is_valid([2, 7, 1, 8, 2, 8, 1, 8, 2, 8, 4, 5, 9, 0, 4, 5, 2]))
print(is_valid([2, 7, 1, 8, 2, 8, 1, 8, 2, 8, 4, 5, 9, 0, 4]))
print(is_valid(['I', 'N', 'O', 'A', 'I', 'L', 'L', 'T', 'R', 'X', 'I', 'I', 'N', 'X', 'F', 'T']))
print(is_valid(['T', 'I', 'N', 'I', 'X', 'R', 'O', 'F', 'T', 'I', 'N', 'I', 'X', 'L', 'L', 'A']))
print(is_valid([]))
How about this, creating an iter from the list and searching forward on that iter until the next matching element is found. Note that this might fail is None can be an element of the list; then you should rather define and compare against a sentinel obj = object().
def is_valid(lst):
it = iter(lst)
for x in it:
if next((y for y in it if y == x), None) is None:
return False
return True
Since we don't actually need the value returned by next, we can also just use any instead, at the same time solving the problem of the default element. Like next, any will consume the iterator just as far as the matching element, if any:
def is_valid(lst):
it = iter(lst)
for x in it:
if not any(y == x for y in it):
return False
return True
This can be further shortened using all instead of the outer for loop:
def is_valid(lst):
it = iter(lst)
return all(any(y == x for y in it) for x in it)
And this can finally be reduced to the equally cryptic and intriguing:
def is_valid(lst):
it = iter(lst)
return all(x in it for x in it)
Each way, each element is visited exactly once, the original list is not changed, little to no extra space, and IMHO it's even somewhat easy to read and understand.
This never was about speed, but anyway: Here are some benchmarks of the different solutions (and some more variations), running the test cases from the question as well as two random lists of 1,000 integers, one valid and one invalid, 10,000 times, on Python 3.8.10:
# with long lists # only short test lists
1.52 is_valid_index 0.22 is_valid_index
3.28 is_valid_next 0.30 is_valid_next
2.78 is_valid_for_for_else 0.13 is_valid_for_for_else
5.26 is_valid_for_any 0.32 is_valid_for_any
5.29 is_valid_all_any 0.38 is_valid_all_any
3.42 is_valid_all_any_if 0.36 is_valid_all_any_if
2.02 is_valid_all_in 0.18 is_valid_all_in
1.97 is_valid_all_in_if 0.17 is_valid_all_in_if
1.87 is_valid_for_in 0.11 is_valid_for_in
Of course, all are O(n). With the long 1000-element-lists, the solution using index is fastest, but the one with x in it is not too bad, either. The any solutions lag somewhat behind, but are about as fast (or slow) as next when using a generator with condition, but still slower than when using plain for loops.
With only the short test-lists, it's a bit different: Here, the solutions using one iterator and for-for-else and for-in are fastest by quite some margin.
Here's my take on the problem. I've optimized for readability, not speed (while keeping it in O(n) of course):
def is_valid(sequence):
iterator = iter(sequence)
for element in iterator:
for other in iterator:
if element == other:
break
else:
return False
return True
Each iteration of the outer loop corresponds to a chunk. When we're out of elements here we ended the sequence at a chunk border, and we can return True. Otherwise, we loop through the iterator until we find a matching element. If we run out of elements (a for-loop that "naturally" terminates, without break, goes into its else) we return False.
And here's another one using itertools. I would not prefer it over the solution above, mostly because of the arcane use of next with a sentinel:
from itertools import dropwhile
def is_valid(iterable):
iterator = iter(iterable)
sentinel = object()
for element in iterator:
if next(dropwhile(lambda x: x != element, iterator), sentinel) is sentinel:
return False
return True
Mutating the list with pop(0) is costly and not needed.
You could use index... this may be particularly fast when the chunks are large:
def is_valid(lst):
i = 0
n = len(list)
while i < n:
try:
i = lst.index(lst[i], i + 1) + 1
except:
return False
return True
It seems like you want to make sure the last "chunk" is closed at the end of the list. This ought to do that:
def is_valid(lst):
search = None
paired = True
for item in lst:
if paired:
search = item
paired = False
elif search == item:
paired = True
return paired
This is O(n), checks each element only one time, so you won't pay a cost for your start not in lst check that is expensive for long input lists.
Below is an alternate, recursive solution to the problem. Basically just checks if the next target is in the list, and skips to that index to check again. I am not an expert here, but wanted to try and contribute a different way to solve the question.
def is_valid(
input_list: list,
target_index: int = 0):
# If we have only one element remaining, or if an empty list is passed initially, there cannot be a pair.
if len(input_list) <= 1:
return False
target = input_list[target_index]
search_range = input_list[target_index + 1 :]
# print(f"target index: {target_index}")
# print(f"target: {target}")
# print(f"search range: {search_range}")
# print("-------------------------------")
if target in search_range:
found_target_sublist_index = search_range.index(target)
# Plus 2: two indexes start at 0 -> off by two
next_target_index = target_index + found_target_sublist_index + 2
if next_target_index == len(input_list):
return True
return is_valid(input_list, next_target_index)
else:
return False
test_one = [2, 7, 1, 8, 2, 8, 1, 8, 2, 8, 4, 5, 9, 0, 4, 5, 2]
test_two = [2, 7, 1, 8, 2, 8, 1, 8, 2, 8, 4, 5, 9, 0, 4]
test_three = ['I', 'N', 'O', 'A', 'I', 'L', 'L', 'T', 'R', 'X', 'I', 'I', 'N', 'X', 'F', 'T']
test_four = ['T', 'I', 'N', 'I', 'X', 'R', 'O', 'F', 'T', 'I', 'N', 'I', 'X', 'L', 'L', 'A']
print(is_valid(test_one))
print(is_valid(test_two))
print(is_valid(test_three))
print(is_valid(test_four))
The question does not fully explain if we need a greedy solution or not.
Consider an example - [1, 2, 1, 1]
if we consider a greedy approach, the solution will find the first sequence as [1, 2, 1] and will be left with [1]. And hence, will return False.
But without a greedy approach, the solution will consider [1, 2, 1, 1] as a full sequence and will return True.
I ran the solution provided by you and it returns False, so I am assuming we need a greedy approach.
So, here is one possible solution:
def is_valid(lst):
to_find = None
for value in lst:
if to_find is None:
to_find = value
continue
if to_find is value:
to_find = None
return to_find is None
# Tests, should print: True, False, True, False, True
print(is_valid([2, 7, 1, 8, 2, 8, 1, 8, 2, 8, 4, 5, 9, 0, 4, 5, 2]))
print(is_valid([2, 7, 1, 8, 2, 8, 1, 8, 2, 8, 4, 5, 9, 0, 4]))
print(is_valid(['I', 'N', 'O', 'A', 'I', 'L', 'L', 'T', 'R', 'X', 'I', 'I', 'N', 'X', 'F', 'T']))
print(is_valid(['T', 'I', 'N', 'I', 'X', 'R', 'O', 'F', 'T', 'I', 'N', 'I', 'X', 'L', 'L', 'A']))
print(is_valid([]))
A short attempt at creating a solution for this:
def isValid(input):
if len(input) == 0:
return True
firstChar = input.pop(0)
if firstChar not in input:
return False
input = input[input.index(firstChar)+1:]
isValid(input)
While I do not think this is the fastest method, I think it is an interesting enough method to include here. Additionally, this can be optimised a bit further by removing the lines:
if firstChar not in input:
return False
And put the code in a try/except block, like so:
def isValid(input):
if len(input) == 0:
return True
firstChar = input.pop(0)
try:
input = input[input.index(firstChar)+1:]
isValid(input)
except:
return False
as this code would give a ValueError if the index doesnt exist
I haven't tested the exact speed difference at the moment, but I am certain it is not the fastest method, but it should be relatively decent speed-wise.

Compare 2 lists while iterating through another list - Python

I have a list source which represents nodes in a network graph. I iterate through the nodes in source to obtain a sub-list of neighbouring nodes. At the same time, all neighbouring nodes are compared against another list watch_list.
I want to create a separate list adjacent that specifies whether the node in source has a neighbour in watch_list. See the code below:
import networkx as nx
import pandas as pd
source = ['A','C','B','D','G','C','B','G']
target = ['B','T','G','A','T','B','H','V']
weight = [2, 1, 6, 6, 3, 3, 2, 1]
watch_list = ['H','D','T']
df = pd.DataFrame([source,target,weight])
df = df.transpose()
df.columns = ['source','target','weight']
G = nx.from_pandas_edgelist(df,'source','target','weight')
adjacent = []
for i in source:
for j in list(nx.all_neighbors(G, i)):
if j in watch_list:
adjacent.append('Y')
else: adjacent.append('N')
print(adjacent)
Running this code returns the following list:
>>> ['N', 'Y', 'Y', 'N', 'N', 'N', 'N', 'Y', 'N', 'N', 'Y', 'N', 'Y', 'N', 'N', 'N', 'N', 'Y', 'N', 'Y', 'N']
The problem is that the code is iterating through the all the neighbours and appending 'Y' or 'N' with each iteration.
How can I control the flow to append 'Y' or 'N' only once, indicating that a node in source either has a neighbour on the watch_list ('Y'), or doesn't ('N').
It seems like a simple flow-control question, but I can't seem to get it right.
Any advice appreciated!
You can use any() and check if any neighbour is in your watch_list:
adjacent = []
for i in source:
if any(x in watch_list for x in list(nx.all_neighbors(G, i))):
adjacent.append('Y')
else:
adjacent.append('N')
print(adjacent)
Result:
['Y', 'Y', 'Y', 'N', 'Y', 'Y', 'Y', 'Y']
This code produces a 'Y' or 'N' for each j:
for j in list(nx.all_neighbors(G, i)):
if j in watch_list:
adjacent.append('Y')
else: adjacent.append('N')
If you just want to know if there is any j for which there is a neighbour, use any:
is_there_any = any(j in watch_list
for j in list(nx.all_neighbors(G, i)))
if is_there_any:
adjacent.append('Y')
else:
adjacent.append('N')
Or, I would rather do simply this:
adjacent = [any(j in watch_list
for j in list(nx.all_neighbors(G, i)))
for i in source]
# adjacent now holds booleans, rather than strings, but I think that is better

"For item in list" loop, need explanation

Okay so I have googled this for days now and still just can't grasp the idea of a "for variable in list" loop! I have been doing the Python course by Codecademy and one exercise I did wanted me to print a 5x5 board of "O"s. Now I successfully did it but I still have no idea how! I will give you the code I did and the result.
The code I wrote is:
board = []
for i in range(0, 5):
board.append(["O"] * 5)
def print_board(board):
for row in board:
print row
print_board(board)
As you can see the goal of the code is to get this result which I did:
['O', 'O', 'O', 'O', 'O']
['O', 'O', 'O', 'O', 'O']
['O', 'O', 'O', 'O', 'O']
['O', 'O', 'O', 'O', 'O']
['O', 'O', 'O', 'O', 'O']
Could someone explain to me how the "for row in board" loop and the "for i in range(0, 5)" loop made this outcome? Thanks!
The general syntax is for item in iterator
That means, that every iteration of the loop, the variables item will contain the next item in iterator.
For example:
lst = [1,2,3,4,5]
for number in lst:
print number #number is 1 then 2 then 3... every iteration its different according to lst
# output:
1
2
3
4
5
OK... now range() is a really nice function that lets you iterate over numbers easily.
It can get a start, end, step and returns a list of numbers that is all the numbers you asked for. For example range(1, 11, 2) will return [1, 3, 5, 7, 9] (11 not included)
for i in range(0, 5):
board.append(["O"] * 5)
Here you're appending ['O', 'O', 'O', 'O', 'O'] (["0"] repeated five times) to the list called board five times. Note that this whole list is appended at once, if you append more such lists, board will be a list of lists, so at each valid index you could find a list.
for row in board:
print row
This iterates over all the entries of board, which, once again, consists of lists.
That's why you're getting five lists each of which contain five letters '0'.

Turning a string into a list with specifications

I want to create a list out of my string in python that would show me how many times a letter is shown in a row inside the string.
for example:
my_string= "google"
i want to create a list that looks like this:
[['g', 1], ['o', 2], ['g', 1], ['l', 1], ['e', 1]]
Thanks!
You could use groupby from itertools:
from itertools import groupby
my_string= "google"
[(c, len(list(i))) for c, i in groupby(my_string)]
You can use a regular expression and a dictionary to find and store the longest string of each letter like this
s = 'google'
nodubs = [s[0]] + [s[x] if s[x-1] != s[x] else '' for x in range(1,len(s))]
nodubs = ''.join(nodubs)
import re
dic = {}
for letter in set(s):
matches = re.findall('%s+' % letter, s)
longest = max([len(x) for x in matches])
dic[letter] = longest
print [[n,dic[n]] for n in nodubs]
Result:
[['g', 1], ['o', 2], ['g', 1], ['l', 1], ['e', 1]]

Categories