Replacing items in nested array and list-tuple - python

Good day to all.
I've been looking for a way to replace items within an array.
Basically I have an array with nested list that looks like that:
array = [ ('a', 'a'), 'c', ('c', 'a'), 'g', 'g', ('h', 'a'), 'a']
Now I'm looking for a way to replace all the appearances of 'a' with 'z'.
and I was hopping to use the following code line in order to achieve that:
new_array = [w.replace('a', 'z') for w in array]
new_array = [ ('z', 'z'), 'c', ('c', 'z'), 'g', 'g', ('h', 'z'), 'a']
Yet, unfortunately I'm receiving the following error:
AttributeError: 'tuple' object has no attribute 'replace'.
I understand the main problem is caused by the use of the tuple (a, x), but they're crucial part of the desired array.
I've spent hours looking for a way around it, And I would highly appreciate any hint in the right direction.
Your help is appreciated!

def replace(value, find, rep):
if isinstance(value, tuple):
return tuple(rep if val==find else val for val in value)
return value
new_array = [replace(val, 'a', 'z') for val in array]
the last ) should be ].

array = [ ('a', 'a'), 'c', ('c', 'a'), 'g', 'g', ('h', 'a'), 'a']
map(lambda l: tuple(i if i != 'a' else 'z' for i in l) if isinstance(l, tuple) else l, array)

Related

How to combine list elements in a tuple?

I am struggling to combine specific list elements from a tuple. Would love any feedback or help! I am new to Python, so apologies if this is not a good question.
If I have a tuple list like this:
tuple_1 = [('A', 'B', 'C', 'D'), ('A', 'H'), ('B', 'C', 'D', 'A')]
I want to combine elements 'B', 'C', and 'D' from every tuple in the list:
tuple_1_new = [('A', 'BCD'), ('A', 'H'), ('BCD', 'A')]
My code looks like this:
next_insert = [(iter(x)) for x in tuple_1]
tuple_1_new = [i + next(next_insert) + next(next_insert) if i == "B" else i for i in next_insert]
but when I print(tuple_1_new), it is giving me an output of:
[<tuple_iterator object at ...>, <tuple_iterator object at ...>, <tuple_iterator object at ...>]
I feel like my code is correct, but I'm confused with this output. Again, sorry if this is a dumb question. Would appreciate any help - thanks!
def foo(arr):
w = "".join(arr)
ind = w.find("BCD")
if ind >= 0:
ans = list(arr)
return tuple(ans[:ind] + ["BCD"] + ans[ind + 3:])
return arr
[foo(x) for x in tuple_1]
# [('A', 'BCD'), ('A', 'H'), ('BCD', 'A')]
Another solution, using generator:
tuple_1 = [("A", "B", "C", "D"), ("A", "H"), ("B", "C", "D", "A")]
def fn(x):
while x:
if x[:3] == ("B", "C", "D"):
yield "".join(x[:3])
x = x[3:]
else:
yield x[0]
x = x[1:]
out = [tuple(fn(t)) for t in tuple_1]
print(out)
Prints:
[('A', 'BCD'), ('A', 'H'), ('BCD', 'A')]
A list comprehension answer:
[tuple([t for t in tup if t not in ['B', 'C', 'D']] + [''.join([t for t in tup if t in ['B', 'C', 'D']])]) for tup in tuple_1]
Although not quite getting the desired output, prints:
[('A', 'BCD'), ('A', 'H', ''), ('A', 'BCD')]
Note: In a 'simple' list comprehension, the 'for x in iterable_name' creates a processing loop using 'x' (or a collection of names if expanding a tuple or performing a zip extraction) as variable(s) in each loop.
When performing list comprehension within a list comprehension (for loop inside for loop), each loop will contribute one or more variables, which obviously must not incur a name collision.
Assuming the strings are single letters like in your example:
tuple_1_new = [tuple(' '.join(t).replace('B C D', 'BCD').split())
for t in tuple_1]
Or with Regen:
tuple_1_new = [tuple(re.findall('BCD|.', ''.join(t)))
for t in tuple_1]

product of list of list of letter [[a,b],[c,d],[a,n]]

I have list of posiple letter for each letter in a word..and I want to find all possiple words.
for example the input is [[l,b],[e,d],[s,t]] this represent a word of 3 letter wher first letter could be l or b, second letter could be e or d and third letter is s or t. I wont the out put to be the product of these lists [les,let,bet,...and so on]. the list could be any length not only three.
I tried
res = list(map(prod, zip(test_list)))
but I get
[<itertools.product object at 0x0000024F65AEC600>, <itertools.product object at 0x0000024F65AEC640>, <itertools.product object at 0x0000024F65AEC680>, <itertools.product object at 0x0000024F65AEC6C0>]
I tried
word1=list(product(letter[0],letter[1],letter[2]))
it works perfectly but I want the code to accept any length pf list
You don't want to zip the test_list, just pass each element of it as an argument to product using the * operator:
>>> test_list = [['l','b'],['e','d'],['s','t']]
>>> import itertools
>>> list(itertools.product(*test_list))
[('l', 'e', 's'), ('l', 'e', 't'), ('l', 'd', 's'), ('l', 'd', 't'), ('b', 'e', 's'), ('b', 'e', 't'), ('b', 'd', 's'), ('b', 'd', 't')]
If you want the result to be in string form, use join:
>>> [''.join(p) for p in itertools.product(*test_list)]
['les', 'let', 'lds', 'ldt', 'bes', 'bet', 'bds', 'bdt']

Why reading/unpacking data from itertools.permutation changed its attribute/content?

I am trying to use the permutation feature from itertools, then I noticed. If I try to unpack/read the data from permutation, it changes some attribute info
from itertools import permutations
a = permutations('abc')
print(('a', 'b', 'c') in a)
for x in a:
print(x)
print(('a', 'b', 'c') in a)
for x in a:
print(x)
Output:
True
('a', 'c', 'b')
('b', 'a', 'c')
('b', 'c', 'a')
('c', 'a', 'b')
('c', 'b', 'a')
False
How come does this happen? I checked out the official page, and cannot find any clue.
My environment is pycharm with python 3.7.4
As others aready said, the problem is that a is not a list, but a generator; that is, a sequence that gets used up as you iterate over it -- hence you can only iterate over it once.
If you look carefully, you'll see that your first print loop only printed five of the six permutations; the first permutation disappeared when you checked it against ('a', 'b', 'c') in your first print statement. The for-loop then prints out what's left, and the rest of your code is trying to drink from an empty cup.
To get the behavior you expect, make a into a list like this:
a = list(permutations('abc'))
And when you get a chance, read up on generators, iterators, and "comprehensions"; they're everywhere in Python (often hidden in plain sight), and they're great.
Get rid from generator and convert the output to list since the comparison is vanishing because it used already. itertools.permutation is just an iterator which is shifting to next when you use one value in comparison.
CODE:
from itertools import permutations
a = list(permutations('abc'))
print(('a', 'b', 'c') in a)
for x in a:
print(x)
print(('a', 'b', 'c') in a)
for x in a:
print(x)
OUTPUT:
True
('a', 'b', 'c')
('a', 'c', 'b')
('b', 'a', 'c')
('b', 'c', 'a')
('c', 'a', 'b')
('c', 'b', 'a')
True
('a', 'b', 'c')
('a', 'c', 'b')
('b', 'a', 'c')
('b', 'c', 'a')
('c', 'a', 'b')
('c', 'b', 'a')

Append all possibilities from sequences with numbers

I have a question that is consuming my brain. Let us suppose that the variable I stores a sequence, and the variable II another one, and the variable III another one too. The variable one will represent the number 1, the next 2 and the next 3; and then I have another key variable with random characters of these 3 sequences. Giving that fact, I can easily translate the characters of this key variable in the correspondent numbers. In the example, x = 'afh', than, it is the same to say that x = '123', because A OR B OR C = 1, and so on.
Now comes the complicated part:
When the key variable x is translated into numbers, each character individually, I can also return characters randomly from the result. For example: x = '123', then I can return a list like ['a','e','f'], or ['b','d','i'], especially if I use random.choice(). From this, what I couldn't figure out how to do yet is:
How can I append into a list ALL THE POSSIBLE VARIATIONS from the variables I, II, III. For example:
['adg','beh','cfi','aei','ceg',...]
I know how to print endlessly random combinations, but in this case, I get repetitions, and I don't want them. I want to append to a list exactly all the possible variations between I, II and III, because when they're translated into numbers, I can return any character from the correspondent sequence. Well, I hope my example is self-explainable. I thank you all very much for the attention!
I = 'abc' # 1
II = 'def' # 2
III = 'ghi' # 3
x = 'afh' # Random possibility: It could be an input.
L = []
LL = []
for i in range(len(x)):
if x[i] in I:
L.append(1)
if x[i] in II:
L.append(2)
if x[i] in III:
L.append(3)
for i in range(len(L)): # Here lies the mistery...
if L[i] == 1:
LL.append(I)
if L[i] == 2:
LL.append(II)
if L[i] == 3:
LL.append(III)
print L
print LL
The output is:
[1, 2, 3]
['abc', 'def', 'ghi']
Here's how I would rewrite your code. Lengthy if statements like yours are a big code smell. I put the sequences into a tuple and used a single loop. I also replaced the second loop with a list comprehension.
By the way, you could also simplify the indexing if you used zero based indexing like a sensible person.
I = 'abc' # 1
II = 'def' # 2
III = 'ghi' # 3
x = 'afh' # Random possibility: It could be an input.
L = []
LL = []
lists = I, II, III
for c in x:
for i, seq in enumerate(lists):
if c in seq:
L.append(i+1)
LL = [lists[i-1] for i in L]
print L
print LL
Also, be sure to check out the itertools module, and in particular the product function. It's not clear exactly what you mean, but product gives you all combinations of an item from each of a list of sequences.
Thank you very much Antimony! The answer is exactly product() from itertools. The code with it is bloody far more simple:
from itertools import *
I = 'abc' # 1
II = 'def' # 2
III = 'ghi' # 3
IV = product(I,II,III)
for i in IV:
print i
And the output is exactly what I wanted, every possible combination:
('a', 'd', 'g')
('a', 'd', 'h')
('a', 'd', 'i')
('a', 'e', 'g')
('a', 'e', 'h')
('a', 'e', 'i')
('a', 'f', 'g')
('a', 'f', 'h')
('a', 'f', 'i')
('b', 'd', 'g')
('b', 'd', 'h')
('b', 'd', 'i')
('b', 'e', 'g')
('b', 'e', 'h')
('b', 'e', 'i')
('b', 'f', 'g')
('b', 'f', 'h')
('b', 'f', 'i')
('c', 'd', 'g')
('c', 'd', 'h')
('c', 'd', 'i')
('c', 'e', 'g')
('c', 'e', 'h')
('c', 'e', 'i')
('c', 'f', 'g')
('c', 'f', 'h')
('c', 'f', 'i')
python 3.2
[(i,v,c) for i in I for v in II for c in III]

Looping through a list of strings and tuples and appending unique combinations

I have been working on this looping problem for a bit now. How do I loop through a list containing a single string and tuple, while appending the tuple to the preceding string? For example:
gen = ['A', ('x', 'y'), ('t', 'u'), 'B', ('y', 't'), 'B', ('a', 'z')]
fam = ['A', 'B']
Fortunately fam also contains the single strings imbeded within gen. In the end I would like the following.
result = [('A',('x','y')), ('A', ('t', 'u')), ('B', ('y', 't')), ('B', ('a', 'z'))
Notice that the tuples following a single string (e.g. 'A') are appending to it.
How do I loop through gen so that the tuples are appending with single strings preceeding it? So far, I have something like the following. Which appends all the combinations in the gen, and then some. I foolishly created a duplicate gen, i.e. gen2 to help with looping, to no avail.
gen = ['A', ('x', 'y'), ('t', 'u'), 'B', ('y', 't'), 'B', ('a', 'z')]
fam = ['A', 'B']
gen2 = ['A', ('x', 'y'), ('t', 'u'), 'B', ('y', 't'), 'B', ('a', 'z')]
result = []
for f in fam:
for g in gen:
if len(g) == 2:
for g2 in gen2:
if g2 == f:
result.append((g2,f))
print result
I apologize if my ramble is too confusing. I appreciate any insight.
You can do it in a single loop and without using fam if you keep track of the last string you came across. It only works properly if the first element of gen is a string, though.
gen = ['A', ('x', 'y'), ('t', 'u'), 'B', ('y', 't'), 'B', ('a', 'z')]
result = []
lastStringSeen = None
for i in gen:
if isinstance(i, str):
lastStringSeen = i
else: #must be a tuple
result.append((lastStringSeen, i))
print result
output:
[('A', ('x', 'y')), ('A', ('t', 'u')), ('B', ('y', 't')), ('B', ('a', 'z'))]

Categories

Resources