Remove all elements from an array python - python-3.x

1) The question I'm working on:
Write an algorithm for a function called removeAll which takes 3 parameters: an array of array type, a count of elements in the array, and a value. As with the remove method we discussed in class, elements passed the count of elements are stored as None. This function should remove all occurrences of value and then shift the remaining data down. The last populated element in the array should then be set to None. The function then returns the count of “valid” (i.e. non-removed) data elements left. This function should do the removal “by hand” and SHOULD NOT use the remove method.
2) Below I have what I think works for the question, but it seems inefficient and repetitive. Is there any way to simplify it?
'''
def myremove(mylist, elements, val):
for i in range(elements): # Changes all val that needs to be removed to None
if mylist[i] == val:
mylist[i] = None
for i in range(elements):
if mylist[i] is None: # Moves elements remaining left
for j in range(i, elements- 1):
mylist[j] = mylist[j + 1]
mylist[elements- 1] = None
while mylist[0] is None: # If the first element is None move left until it is not
for j in range(i, elements - 1):
mylist[j] = mylist[j + 1]
mylist[elements - 1] = None
for i in range(elements): # Counts remaining elements
if mylist[i] is None:
elements -= 1
return mylist, elements
"""
"""
# Testing the function
print(removeAll([8, 'N', 24, 16, 1, 'N'], 6, 'N'))
print(removeAll([1, 'V', 3, 4, 2, 'V'], 6, 3))
print(removeAll([0, 'D', 5, 6, 9, 'D'], 6, 'N'))
print(removeAll(['X', 'X', 7, 'X', 'C', 'X'], 6, 'X'))
"""
"""
OUTPUT
([8, 24, 16, 1, None, None], 4)
([1, 'V', 4, 2, 'V', None], 5)
([0, 'D', 5, 6, 9, 'D'], 6)
([7, 'C', None, None, None, None], 2)
"""

You can just sort the list based on whether or not the value equals the hole value.
l = [8, 'N', 24, 16, 1, 'N']
sorted(l, key=lambda x: x == 'N')
output:
[8, 24, 16, 1, 'N', 'N']
If you need None instead of the hole value in the output, use a list comprehension and then sort based on None first.
l = [i if i != 'N' else None for i in [8, 'N', 24, 16, 1, 'N']]
sorted(l, key=lambda x: x == None)
[8, 24, 16, 1, None, None]
Then all thats left is to add in the count which you can just get by counting how many elements are None and subtract that from your input parameter.
def myremove(mylist, elements, val):
ret_list = sorted([i if i != val else None for i in mylist], key=lambda x: x == None)
return ret_list, elements - ret_list.count(None)

Related

Python: from list group by elements after a specific trigger element [duplicate]

This question already has answers here:
Python3: How can I split a list based on condition?
(2 answers)
Closed last year.
I have a list like
a=['a',2,'[abcd]','bb',4,5,'kk','[efgh]',6,7,'no','[ijkl]',4,5,'lo']
So here we want group by after each '[]'
so the expected one would be
[['a',2],{'abcd': ['bb',4,5,'kk']},{'efgh': [6,7,'no']},{'ijkl': [4,5,'lo']}]
Any help would be appriciable
You can use groupby:
from itertools import groupby
a=['a',2,'[abcd]','bb',4,5,'kk','[efgh]',6,7,'no','[ijkl]',4,5,'lo']
def group_by_tag(li):
def tag_counter(x):
if isinstance(x, str) and x.startswith('[') and x.endswith(']'):
tag_counter.cnt += 1
return tag_counter.cnt
tag_counter.cnt = 0
return groupby(li, key=tag_counter)
Which you can use to make a list of tuples for each segment partitioned by the [tag]:
>>> x=[(k,list(l)) for k, l in group_by_tag(a)]
>>> x
[(0, ['a', 2]), (1, ['[abcd]', 'bb', 4, 5, 'kk']), (2, ['[efgh]', 6, 7, 'no']), (3, ['[ijkl]', 4, 5, 'lo'])]
And then create your desired mixed-type list from that:
>>> [v if k==0 else {v[0].strip('[]'):v[1:]} for k,v in x]
[['a', 2], {'abcd': ['bb', 4, 5, 'kk']}, {'efgh': [6, 7, 'no']}, {'ijkl': [4, 5, 'lo']}]
But consider that it is usually better to have a list of the same type of object to make processing that list easier.
If you want that, you could do:
>>> [{'no_tag':v} if k==0 else {v[0].strip('[]'):v[1:]} for k,v in x]
[{'no_tag': ['a', 2]}, {'abcd': ['bb', 4, 5, 'kk']}, {'efgh': [6, 7, 'no']}, {'ijkl': [4, 5, 'lo']}]
By "=>" I assume you want a dictionary if there is a preceding keyword and key be the word enclosed within the square brackets (if that's not what you intended feel free to comment and I'll edit this post)
import re
def sort(iterable):
result = {}
governing_match = None
for each in list(iterable):
match = re.findall(r"\[.{1,}\]", str(each))
if len(match) > 0:
governing_match = match[0][1:-1]
result[governing_match] = []
continue
result[governing_match].append(each)
return result
a=['[foo]', 'a' , 2 ,'[abcd]','bb',4,5,'kk','[efgh]',6,7,'no','[ijkl]',4,5,'lo']
for (k, v) in sort(a).items():
print(f"{k} : {v}")
Result :
foo : ['a', 2]
abcd : ['bb', 4, 5, 'kk']
efgh : [6, 7, 'no']
ijkl : [4, 5, 'lo']
The limitation of this is that every sequence should start with an element that is enclosed within square brackets.
You can use pairwise for that:
from itertools import pairwise
a=['a',2,'[abcd]','bb',4,5,'kk','[efgh]',6,7,'no','[ijkl]',4,5,'lo']
bracket_indices = [i for i, x in enumerate(a) if isinstance(x, str)
and x.startswith('[') and x.endswith(']')]
bracket_indices.append(len(a))
output = [a[:bracket_indices[0]]] # First item is special cased
output.extend({a[i][1:-1]: a[i+1:j]} for i, j in pairwise(bracket_indices))

python3 find value inside array inside another array

I have my array is : Li = [[1,2,3],[4,5,6],[7,8,9]] how can check if value exist in an array . Example
if 5 exist in Li return Li[1][1] so I can change the value of that item by making Li[1][1]=
"X"
If your nested list is always a 2D matrix of numbers, then you can find the indices fairly easily:
def find_indices(nested_list, value):
for i, inner_list in enumerate(nested_list):
for j, item in enumerate(inner_list):
if item == value:
return (i,j) # return a tuple containing the indices
Li = [[1,2,3],[4,5,6],[7,8,9]]
print(find_indices(Li, 5))
This example uses the enumerate function in Python, which gives you the index and item inside of an iterable object.
To be honest it is hard to understand what u really want, or if u urself even know that. Here is some input that might help u:
from typing import List
def is_value_in_list_of_lists(
value_to_check: int, list_of_lists: List[List[int]]
) -> bool:
for v in list_of_lists: # v::List[int]
if value_to_check in v:
return True
return False
def replace_all_occurrences_of_value_in_list_of_lists(
value_to_check: int, value_to_replace_with: str, list_of_lists: List[List[int]]
) -> List[List[int]]:
if is_value_in_list_of_lists(value_to_check, list_of_lists):
modified_list_of_lists = []
for v in list_of_lists: # v::List[int]
if value_to_check not in v:
modified_list_of_lists.append(v)
else:
# modify list
v_modified = []
for val in v: # val::int
if val == value_to_check:
v_modified.append(value_to_replace_with)
else:
v_modified.append(val)
modified_list_of_lists.append(v_modified)
return modified_list_of_lists
else:
return list_of_lists
if __name__ == "__main__":
lists = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
# True
print(is_value_in_list_of_lists(5, lists))
# [[1, 2, 3], [4, 'X', 6], [7, 8, 9]]
print(replace_all_occurrences_of_value_in_list_of_lists(5, "X", lists))
# oneliner
# [[1, 2, 3], [4, 'X', 6], [7, 8, 9]]
print(list([*map(lambda x: "X" if x == 5 else x, y)] for y in lists))

Using a shorter list as values

Hello I am trying to use a shorter list as a value in a dictionary can anyone please help?
string = input("Input DNA Sequence: ")
sequence = [string[e:e+3] for e in range(0, len(string), 3)]
p_residue = list("WYS")
Input: TGGTACTCTTTCTTCACA
Output: {TGG:W,TAC:Y,TCT:S,TTC:W,TTC:Y,ACA:S}
I've tried cycle but I can't seem to make it work.
You can use cycle if you zip p_residue onto your sequence.
from itertools import cycle
def split_str_every(n, seq):
return [seq[i:i+n] for i in range(0, len(seq), n)]
def combine(seq, residue):
return zip(sequence, cycle(p_residue))
sequence = split_str_every(3, "TGGTACTCTTTCTTCACA")
p_residue = ["W", "Y", "S"]
out = combine(sequence, p_residue)
print(dict(out))
Gives:
{'TGG': 'W', 'TAC': 'Y', 'TCT': 'S', 'TTC': 'Y', 'ACA': 'S'}
Which, as you can see, dictionaries don't allow duplicate keys by definition. We can use defaultdics to circumvent this problem. To fix this, we import defaultdict and redefine our combine function:
from collections import defaultdict
def combine(seq, residue):
zipped = zip(sequence, cycle(p_residue))
ddict = defaultdict(list)
for k, v in zipped:
ddict[k].append(v)
return dict(ddict.items())
print(combine(sequence, p_residue))
Now gives the correct answer. Notice that the key TTC stores a list containing both Y & W:
{'TGG': ['W'], 'TAC': ['Y'], 'TCT': ['S'], 'TTC': ['W', 'Y'], 'ACA': ['S']}
Use
sequence = {
string[e:e+3]: p_residue[(e//3) % len(p_residue)]
for e in range(0, len(string), 3)
}
Output
{'TGG': 'W', 'TAC': 'Y', 'TCT': 'S', 'TTC': 'Y', 'ACA': 'S'}
To understand better,
e is one of [0, 3, 6, 9, 12, 15]
e//3 is integer division, so, [0, 1, 2, 3, 4, 5]
(e//3) % 3 is to keep it to residue length, so, [0, 1, 2, 0, 1, 2]
This mathematical approach induces a cycle

flatten a nested list with indices in python

I have a list ['','','',['',[['a','b']['c']]],[[['a','b'],['c']]],[[['d']]]]
I want to flatten the list with indices and the output should be as follows:
flat list=['','','','','a','b','c','a','b','c','d']
indices=[0,1,2,3,3,3,3,4,4,4,5]
How to do this?
I have tried this:
def flat(nums):
res = []
index = []
for i in range(len(nums)):
if isinstance(nums[i], list):
res.extend(nums[i])
index.extend([i]*len(nums[i]))
else:
res.append(nums[i])
index.append(i)
return res,index
But this doesn't work as expected.
TL;DR
This implementation handles nested iterables with unbounded depth:
def enumerate_items_from(iterable):
cursor_stack = [iter(iterable)]
item_index = -1
while cursor_stack:
sub_iterable = cursor_stack[-1]
try:
item = next(sub_iterable)
except StopIteration:
cursor_stack.pop()
continue
if len(cursor_stack) == 1:
item_index += 1
if not isinstance(item, str):
try:
cursor_stack.append(iter(item))
continue
except TypeError:
pass
yield item, item_index
def flat(iterable):
return map(list, zip(*enumerate_items_from(a)))
Which can be used to produce the desired output:
>>> nested = ['', '', '', ['', [['a', 'b'], ['c']]], [[['a', 'b'], ['c']]], [[['d']]]]
>>> flat_list, item_indexes = flat(nested)
>>> print(item_indexes)
[0, 1, 2, 3, 3, 3, 3, 4, 4, 4, 5]
>>> print(flat_list)
['', '', '', '', 'a', 'b', 'c', 'a', 'b', 'c', 'd']
Note that you should probably put the index first to mimic what enumerate does. It would be easier to use for people that already know enumerate.
Important remark unless you are certain your lists will not be nested too much, you shouldn't use any recursion-based solution. Otherwise as soon as you'll have a nested list with depth greater than 1000, your code will crash. I explain this here. Note that a simple call to str(list) will crash on a test case with depth > 1000 (for some python implementations it's more than that, but it's always bounded). The typical exception you'll have when using recursion-based solutions is (this in short is due to how python call stack works):
RecursionError: maximum recursion depth exceeded ...
Implementation details
I'll go step by step, first we will flatten a list, then we will output both the flattened list and the depth of all items, and finally we will output both the list and the corresponding item indexes in the "main list".
Flattening list
That being said, this is actually quite interesting as the iterative solution is perfectly designed for that, you can take a simple (non-recursive) list flattening algorithm:
def flatten(iterable):
return list(items_from(iterable))
def items_from(iterable):
cursor_stack = [iter(iterable)]
while cursor_stack:
sub_iterable = cursor_stack[-1]
try:
item = next(sub_iterable)
except StopIteration: # post-order
cursor_stack.pop()
continue
if isinstance(item, list): # pre-order
cursor_stack.append(iter(item))
else:
yield item # in-order
Computing depth
We can have access to the depth by looking at the stack size, depth = len(cursor_stack) - 1
else:
yield item, len(cursor_stack) - 1 # in-order
This will return an iterative on pairs (item, depth), if we need to separate this result in two iterators we can use the zip function:
>>> a = [1, 2, 3, [4 , [[5, 6], [7]]], [[[8, 9], [10]]], [[[11]]]]
>>> flatten(a)
[(1, 0), (2, 0), (3, 0), (4, 1), (5, 3), (6, 3), (7, 3), (8, 3), (9, 3), (10, 3), (11, 3)]
>>> flat_list, depths = zip(*flatten(a))
>>> print(flat_list)
(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)
>>> print(depths)
(0, 0, 0, 1, 3, 3, 3, 3, 3, 3, 3)
We will now do something similar to have item indexes instead of the depth.
Computing item indexes
To instead compute item indexes (in the main list), you'll need to count the number of items you've seen so far, which can be done by adding 1 to an item_index every time we iterate over an item that is at depth 0 (when the stack size is equal to 1):
def flatten(iterable):
return list(items_from(iterable))
def items_from(iterable):
cursor_stack = [iter(iterable)]
item_index = -1
while cursor_stack:
sub_iterable = cursor_stack[-1]
try:
item = next(sub_iterable)
except StopIteration: # post-order
cursor_stack.pop()
continue
if len(cursor_stack) == 1: # If current item is in "main" list
item_index += 1
if isinstance(item, list): # pre-order
cursor_stack.append(iter(item))
else:
yield item, item_index # in-order
Similarly we will break pairs in two itératifs using ˋzip, we will also use ˋmap to transform both iterators to lists:
>>> a = [1, 2, 3, [4 , [[5, 6], [7]]], [[[8, 9], [10]]], [[[11]]]]
>>> flat_list, item_indexes = map(list, zip(*flatten(a)))
>>> print(flat_list)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
>>> print(item_indexes)
[0, 1, 2, 3, 3, 3, 3, 4, 4, 4, 5]
improvement — Handling iterable inputs
Being able to take a broader palette of nested iterables as input could be desirable (especially if you build this for others to use). For example, the current implementation doesn't work as expected if we have nested iterables as input, for example:
>>> a = iter([1, '2', 3, iter([4, [[5, 6], [7]]])])
>>> flat_list, item_indexes = map(list, zip(*flatten(a)))
>>> print(flat_list)
[1, '2', 3, <list_iterator object at 0x100f6a390>]
>>> print(item_indexes)
[0, 1, 2, 3]
If we want this to work we need to be a bit careful because strings are iterable but we want them to be considered as atomic items (not a as lists of characters). Instead of assuming the input is a list as we did before:
if isinstance(item, list): # pre-order
cursor_stack.append(iter(item))
else:
yield item, item_index # in-order
We will not inspect the input type, instead we will try to use it as if it was an iterable and if it fails we will know that it’s not an iterable (duck typing):
if not isinstance(item, str):
try:
cursor_stack.append(iter(item))
continue
# item is not an iterable object:
except TypeError:
pass
yield item, item_index
With this implementation, we have:
>>> a = iter([1, 2, 3, iter([4, [[5, 6], [7]]])])
>>> flat_list, item_indexes = map(list, zip(*flatten(a)))
>>> print(flat_list)
[1, 2, 3, 4, 5, 6, 7]
>>> print(item_indexes)
[0, 1, 2, 3, 3, 3, 3]
Building test cases
If you need to generate tests cases with large depths, you can use this piece of code:
def build_deep_list(depth):
"""Returns a list of the form $l_{depth} = [depth-1, l_{depth-1}]$
with $depth > 1$ and $l_0 = [0]$.
"""
sub_list = [0]
for d in range(1, depth):
sub_list = [d, sub_list]
return sub_list
You can use this to make sure my implementation doesn't crash when the depth is large:
a = build_deep_list(1200)
flat_list, item_indexes = map(list, zip(*flatten(a)))
We can also check that we can't print such a list by using the str function:
>>> a = build_deep_list(1200)
>>> str(a)
RecursionError: maximum recursion depth exceeded while getting the repr of an object
Function repr is called by str(list) on every element from the input list.
Concluding remarks
In the end I agree that recursive implementations are way easier to read (as the call stack does half the hard work for us), but when implementing low level function like that I think it is a good investment to have a code that works in all cases (or at least all the cases you can think of). Especially when the solution is not that hard. That's also a way not to forget how to write non-recursive code working on tree-like structures (which may not happen a lot unless you are implementing data structures yourself, but that's a good exercise).
Note that everything I say “against” recursion is only true because python doesn't optimize call stack usage when facing recursion: Tail Recursion Elimination in Python. Whereas many compiled languages do Tail Call recursion Optimization (TCO). Which means that even if you write the perfect tail-recursive function in python, it will crash on deeply nested lists.
If you need more details on the list flattening algorithm you can refer to the post I linked.
Simple and elegant solution:
def flat(main_list):
res = []
index = []
for main_index in range(len(main_list)):
# Check if element is a String
if isinstance(main_list[main_index], str):
res.append(main_list[main_index])
index.append(main_index)
# Check if element is a List
else:
sub_list = str(main_list[main_index]).replace('[', '').replace(']', '').replace(" ", '').replace("'", '').split(',')
res += sub_list
index += ([main_index] * len(sub_list))
return res, index
this does the job, but if you want it to be just returned then I'll enhance it for you
from pprint import pprint
ar = ["","","",["",[["a","b"],["c"]]],[[["a","b"],["c"]]],[[["d"]]]]
flat = []
indices= []
def squash(arr,indx=-1):
for ind,item in enumerate(arr):
if isinstance(item, list):
squash(item,ind if indx==-1 else indx)
else:
flat.append(item)
indices.append(ind if indx==-1 else indx)
squash(ar)
pprint(ar)
pprint(flat)
pprint(indices)
EDIT
and this is if you don't want to keep the lists in memory and return them
from pprint import pprint
ar = ["","","",["",[["a","b"],["c"]]],[[["a","b"],["c"]]],[[["d"]]]]
def squash(arr,indx=-1,fl=[],indc=[]):
for ind,item in enumerate(arr):
if isinstance(item, list):
fl,indc = squash(item,ind if indx==-1 else indx, fl, indc)
else:
fl.append(item)
indc.append(ind if indx==-1 else indx)
return fl,indc
flat,indices = squash(ar)
pprint(ar)
pprint(flat)
pprint(indices)
I'm not expecting you would need more than 1k recursion depth which is the default setting

Print a Pretty Tree

I have extracted a list from a tree using BFS
solution= [[6], [0, 7], [None, 3, None, 8], [2, 5, None, 9], [1, None, 4, None, None, None], [None, None, None, None]]
How do i print it as a horizontal tree?
I was trying to print it using
def _print_tree(n=0,height,solution):
if n > height:
return
for j in range(len(solution[n])):
if solution[n][j]== None:
print(' ' * (2 ** (height - n + 1) - 1),end='')
else:
print(' ' * (2 ** (height - n + 1) - 1), end='')
print(' ',solution[n][j], end='')
But it gives
I've played around and here is the result
nonechar = 'N'
spacechar = '_'
solution = [[6], [0, 7], [None, 3, None, 8], [2, 5, None, 9], [1, None, 4, None, None, None], [None, None, None, 4],[None, 3]]
for i in range(1, len(solution)):
for j in range(len(solution[i-1])):
if (solution[i-1][j] == None):
solution[i].insert(2*j, None)
solution[i].insert(2*j+1, None)
N = len(solution[-1]) * 2 - 1
offset = (N - 1) / 2
spacing = 0
for i in range(len(solution)):
line = spacechar * int(offset)
for j in range(len(solution[i])):
if (solution[i][j] == None):
line += nonechar
else:
line += str(solution[i][j])
if (j != len(solution[i]) - 1):
line += spacechar * int(spacing)
line += spacechar * int(offset)
print(line)
spacing = offset
offset = (offset - 1) / 2
What I basically did is fill the solution list with the missing data so that each next sub-list has two times more values than the previous one. For each j-th element of the i-th sub-list there are values under [i+1][2*j] and [i+1][2*j+1]. Then I just print out the result using ASCII art, having calculated required offsets and spacing. The limitations here are that you can only use digits 0-9 in order not to screw up my tree. You'll have to figure out the way to solve it on your own :)
Oh, yeah. The output looks like this (feel free to change characters for missing values and spaces):
_______________________________________________________________6_______________________________________________________________
_______________________________0_______________________________________________________________7_______________________________
_______________N_______________________________3_______________________________N_______________________________8_______________
_______N_______________N_______________2_______________5_______________N_______________N_______________N_______________9_______
___N_______N_______N_______N_______1_______N_______4_______N_______N_______N_______N_______N_______N_______N_______N_______N___
_N___N___N___N___N___N___N___N___N___N___N___N___N___4___N___N___N___N___N___N___N___N___N___N___N___N___N___N___N___N___N___N_
N_N_N_N_N_N_N_N_N_N_N_N_N_N_N_N_N_N_N_N_N_N_N_N_N_N_N_3_N_N_N_N_N_N_N_N_N_N_N_N_N_N_N_N_N_N_N_N_N_N_N_N_N_N_N_N_N_N_N_N_N_N_N_N

Resources