Python from tuples to strings - python

new to the python programming, havin some difficulties figuring this out.
I'm trying to convert tuples into strings, for example ('h','e',4) into 'he4'. i've submitted a version using the .join function, and i'm required to come up with another ver. i'm given the following:
def filter(pred, seq): # keeps elements that satisfy predicate
if seq == ():
return ()
elif pred(seq[0]):
return (seq[0],) + filter(pred, seq[1:])
else:
return filter(pred, seq[1:])
def accumulate(fn, initial, seq):
if seq == ():
return initial
else:
return fn(seq[0], accumulate(fn, initial, seq[1:]))
hints on how to use the following to come up with conversion of tuples to strings?

The given filter is useless for this but the given accumulate can be used easily:
>>> t = ('h','e',4)
>>> accumulate(lambda x, s: str(x) + s, '', t)
'he4'

Just loop through the tuple.
#tup stores your tuple
string = ''
for s in tuple :
string+=s
Here you are going through the tuple and adding each element of it into a new string.

1) Use reduce function:
>>> t = ('h','e',4)
>>> reduce(lambda x,y: str(x)+str(y), t, '')
'he4'
2) Use foolish recursion:
>>> def str_by_recursion(t,s=''):
if not t: return ''
return str(t[0]) + str_by_recursion(t[1:])
>>> str_by_recursion(t)
'he4'

You can use map to and join.
tup = ('h','e',4)
map_str = map(str, tup)
print(''.join(map_str))
Map takes two arguments. First argument is the function which has to be used for each element of the list. Second argument is the iterable.

Related

To make a recursive function with challenging constraints

I would like to make a function with an input string (for example 'abcdef'), and returns it in reverse order 'fedcba'.
However, the challenge is that the function
must use a recursive function
is without using for-loop
is without any operators
is without list slicing
This is my attempt which does not work:
def reverse(s: str) -> str
if len(s) == 0:
return None
return
How do I use the recursive function here to reverse order? I tried to think of it but i'm new to recursive calls
"without using for loops or any operators or list slicing" seems like a weird requirement, but the following function will do:
>>> def reverse(s):
... head, *tail = s
... if tail:
... return f'{reverse(tail)}{head}'
... else:
... return head
...
>>> reverse('abcdef')
'fedcba'
In the scope of lexical analysis, * is regarded as an operator, so we can replace head, *tail = s with the following:
import re
def reverse(s):
head, tail = re.split('(?!^)', s, maxsplit=1)
[...]
Or, alternatively:
def reverse(s):
__, head, tail = s.partition(next(iter(s))
[...]
Or, yet another alternative:
def reverse(s):
s = iter(s)
head, tail = next(s), ''.join(s)
[...]
Edit: I have removed the '+' operator, and also the lstrip() which does not work on repeated characters in the string (thanks #philosofool)
Here's one way to do it without list slicing. And to clarify s[0] is list indexing not list slicing, correct?
def reverse(s):
if len(s)==1:
return s
else:
s1 = list(s)
del s1[0]
return ''.join([reverse(''.join(s1)), s[0]])
reverse('abccdefg')
output is
'gfedccba'
This is not actually a solution. It meets all the requirements except the recursive one. It's a nice, purely functional solution, but not what OP asked for. Leaving it up in case anyone is interested....
from functools import reduce
def reverse_string(string):
return reduce(lambda x, y: f'{y}{x}', string)
Using only functions
def reverse(strng, pos):
if pos:
next_pos = map(lambda x: x, range(pos,0,-1))
next(next_pos) # skip first
return ''.join((strng[pos],reverse(strng, next(next_pos)))
else:
return strng[pos]
Another one inspired by #Ecin
def reverse(strng : str):
def inner(strng : list):
return ''.join((strng.pop(), inner(strng) if strng else ''))
return inner(list(strng))

a recursion function that return an int

def nested_count(l : 'any nested list of int', a : int) -> int:
c = 0
while len(l) != 0:
for x in l:
if type(x) == int:
if x == a:
c = c + 1
l.remove(x)
nested_count(l,a)
else:
continue
elif type(x) == list:
nested_count(x,a)
return c
this function passed a nested list of ints and a single int as arguments; it returns the number of times the single int argument appears in the nested list argument, for example:
nested_count( [[1,2,[4,[1],8],[1,3,2]],[1,1]], 1 )
returns 5
I am not sure why my function does not work
can someone tell me how to fix it? many thanks.
You are not adding nested_count results to c:
def nested_count(lst, l):
c = 0
for i in lst:
if i == l:
c += 1
elif type(i) == list:
c += nested_count(i, l)
return c
Also it is better to iterate over list with for.
The results of the nested function calls are not used. You probably should replace the lines with c += nested_count(l,a) and c += nested_count(x,a), respectively.
You shouldn't mutate the list while iterate over it and you need to return the result from recursive calls. You could simplify function greatly by checking the type of l and if it's int then returning bool telling if it matches with a. In case l is a list just call nested_count recursively on its' items and sum the result:
def nested_count(l, a):
# Base case
if type(l) == int:
return l == a
return sum(nested_count(x, a) for x in l)
As others have mentioned you need to accumulate the return values from the recursive calls of nested_count to get the correct total.
Also, removing items from a list (or other collection) that you're iterating over can lead to unexpected results, see the SO Python Common Question Removing items from a list while iterating over the list for details and a few relevant SO pages, in particular: Removing from a list while iterating over it.
It's generally preferred to call isinstance rather than type to do type testing. The isinstance function can test for multiple types in one call, it will also return True if the object is a subclass of the specified type.
Here are a couple of one-liners that handle lists or tuples.
def nested_count(l, a):
return sum(nested_count(x, a) if isinstance(x, (list, tuple)) else x == a for x in l)
and
def nested_count(l, a):
return l.count(a) + sum(nested_count(x, a) for x in l if isinstance(x, (list, tuple)))
Why the heterogenous list? Why bother using typing if you're not going to type all the parameters? Why are you mutating the input?
from typing import List
def deep_count_elem (x:int, xs:List) -> int:
# done
if len(xs) == 0:
return 0
# if list, count in this list and recurse
elif isinstance(xs[0], list):
return deep_count_elem(x, xs[0]) + deep_count_elem(x, xs[1:])
# if element matches, add 1
elif x == xs[0]:
return 1 + deep_count_elem(x, xs[1:])
# otherwise add nothing, move to next element
else:
return deep_count_elem(x, xs[1:])
print(deep_count_elem(1, [[1,2,[4,[1],8],[1,3,2]],[1,1]])) # 5

writing a function that return the reversed number

I am trying to write a Python function that get a number as input and returns its reversed number as output. for example: 1234 returns 4321.
this is what I try, but it return only ''
def reverse(num):
L=[]
x=str(num)
L1=list(x)
for i in L1:
L.insert(0,i)
print 'the reversed num is:'
x=''
for i in L:
x.join(i)
return x
any ideas?
def reverse(num):
return str(num)[::-1]
or one line:
lambda x: str(x)[::-1]
Well, the easy solution is this one:
>>> int(str(1234)[::-1])
4321
Your code can be fixed by changing the part
for i in L:
x.join(i)
return x
to
for i in L:
x += i
return x
Alternatively, just replace that section by
return ''.join(L)
What was wrong with your code? Because of wrong indentation, you returned in the first iteration of the for loop. You never assigned a name to x.join(i) so the return value was lost. What you expected join to do I do not know.
First, there is an easier way by converting to string, slicing the string and converting it back to a number.
def reverse(num):
return int(str(num)[::-1])
Second, there are multiple errors in your code:
1) your return statement is in the loop, so it will return after the first iteration;
2) x does not change because x.join() creates a new string and does not modify the string x (which is immutable by the way)
3) no need to convert the string into a list since you can directly iterate over the string (for i in x: ...)
4) join() takes an iterator as an argument. No need for the second loop: return ''.join(L)
thank you all for the helpful ideas.
here is my solution:
def reverse(n):
reverse=0
while(n>0):
dig=n%10
reverse=reverse*10
reverse=reverse+dig
n=n/10
return reverse
def reverse(num)
return str(num)[::-1]
Reverse a string in Python
Other users already gave good answers. Here is a different one, for study purposes.
num = 1234
print "".join(reversed(str(num)))
# 4321
You can convert to int afterwards.

Passing a function with two arguments to filter() in python

Given the following list:
DNA_list = ['ATAT', 'GTGTACGT', 'AAAAGGTT']
I want to filter strings longer than 3 characters. I achieve this with the following code:
With for loop:
long_dna = []
for element in DNA_list:
length = len(element)
if int(length) > 3:
long_dna.append(element)
print long_dna
But I want my code to be more general, so I can later filter strings of any length, so I use a function and for loop:
def get_long(dna_seq, threshold):
return len(dna_seq) > threshold
long_dna_loop2 = []
for element in DNA_list:
if get_long(element, 3) is True:
long_dna_loop2.append(element)
print long_dna_loop2
I want to achieve the same generality using filter() but I cannot achieve this. If I use the above function get_long(), I simply cannot pass arguments to it when I use it with filter(). Is it just not possible or is there a way around it?
My code with filter() for the specific case:
def is_long(dna):
return len(dna) > 3
long_dna_filter = filter(is_long, DNA_list)
Use lambda to provide the threshold, like this:
filter(lambda seq: get_long(seq, 3),
dna_list)
What you are trying to do is known as partial function application: you have a function with multiple arguments (in this case, 2) and want to get a function derived from it with one or more arguments fixed, which you can then pass to filter.
Some languages (especially functional ones) have this functionality "built in". In python, you can use lambdas to do this (as others have shown) or you can use the functools library. In particular, functools.partial:
The partial() is used for partial function application which “freezes” some portion of a function’s arguments and/or keywords resulting in a new object with a simplified signature. For example, partial() can be used to create a callable that behaves like the int() function where the base argument defaults to two:
>>> from functools import partial
>>> basetwo = partial(int, base=2)
>>> basetwo.__doc__ = 'Convert base 2 string to an int.'
>>> basetwo('10010')
18
So you can do:
filter(functools.partial(get_long, treshold=13), DNA_list)
Do you need to use filter()? Why not use a more Pythonic list comprehension?
Example:
>>> DNA_list = ['ATAT', 'GTGTACGT', 'AAAAGGTT']
>>> threshold = 3
>>> long_dna = [dna_seq for dna_seq in DNA_list if len(dna_seq) > threshold]
>>> long_dna
['ATAT', 'GTGTACGT', 'AAAAGGTT']
>>> threshold = 4
>>> [dna_seq for dna_seq in DNA_list if len(dna_seq) > threshold]
['GTGTACGT', 'AAAAGGTT']
This method has the advantage that it's trivial to convert it to a generator which can provide improved memory and execution depending on your application, e.g. if you have a lot of DNA sequences, and you want to iterate over them, realising them as a list will consume a lot of memory in one go. The equivalent generator simply requires replacing square brackets [] with round brackets ():
>>> long_dna = (dna_seq for dna_seq in DNA_list if len(dna_seq) > threshold)
<generator object <genexpr> at 0x7f50de229cd0>
>>> list(long_dna)
['GTGTACGT', 'AAAAGGTT']
In Python 2 this performance improvement is not an option with filter() because it returns a list. In Python 3 filter() returns a filter object more akin to a generator.
You can make is_long return a function, which can accept dna, like this
>>> def is_long(length):
... return lambda dna: len(dna) > length
...
and then use it in filter, like this
>>> filter(is_long(3), DNA_list)
['ATAT', 'GTGTACGT', 'AAAAGGTT']
>>> filter(is_long(4), DNA_list)
['GTGTACGT', 'AAAAGGTT']
Note: Don't use is operator to compare booleans or numbers. Instead rely on the truthiness of the data as much as possible. So, in your case, you could have written your second version like this
if get_long(element, 3):
long_dna_loop2.append(element)
Quoting programming recommendations in PEP-8,
Don't compare boolean values to True or False using == .
Yes: if greeting:
No: if greeting == True:
Worse: if greeting is True:
You can have a more general case.
Since function is an object in python, you can create another function, which returns the function you want.
def f(threshhold):
def g(x):
return len(x)>threshhold
return g #return a function
this_function = f(3)
DNA_list = ['ATAT', 'GTGTACGT', 'AAAAGGTT','AAA','AAAA']
filter(this_function, DNA_list)
output: ['ATAT', 'GTGTACGT', 'AAAAGGTT', 'AAAA']
The g is what you really want and f is the function that create it.
I used different solution using inner function and nonlocal scope like below. I have modified this original code for understanding as my code is different.
Hope this helps. :)
def outerfun():
charlimit = 3
def is_long(dna):
nonlocal charlimit
return len(dna) > charlimit
long_dna_filter = filter(is_long, DNA_list)
return long_dna_filter
Here are a couple of more ways using lambda. The first one uses a default keyword argument to hold the desired length. The second simply embeds the desired length in the lambda body.
#Create a list of strings
s = 'abcdefghi'
data = [s[:i+1] for i in range(len(s))]
print data
thresh = 3
print filter(lambda seq, n=thresh: len(seq) > n, data)
print filter(lambda seq: len(seq) > 5, data)
output
['a', 'ab', 'abc', 'abcd', 'abcde', 'abcdef', 'abcdefg', 'abcdefgh', 'abcdefghi']
['abcd', 'abcde', 'abcdef', 'abcdefg', 'abcdefgh', 'abcdefghi']
['abcdef', 'abcdefg', 'abcdefgh', 'abcdefghi']
In the first example you could also do:
print filter(lambda seq, n=3: len(seq) > n, data)
Similarly, in the second example you could replace the literal 5 with a local (or global) variable, eg:
thresh = 5
print filter(lambda seq: len(seq) > thresh, data)
You could always create a callable that returns a callable suitable for comparisons done by filter as the following example shows:
def main():
dna_list = ['A', 'CA', 'TGATGATAC', 'GGGTAAAATC', 'TCG', 'AGGTCGCT', 'TT',
'GGGTTGGA', 'C', 'TTGGAGGG']
print('\n'.join(filter(length_at_least(3), dna_list)))
def length_at_least(value):
return lambda item: len(item) >= value
# length_at_least = lambda value: lambda item: len(item) >= value
if __name__ == '__main__':
main()

Python - making a function that would add "-" between letters

I'm trying to make a function, f(x), that would add a "-" between each letter:
For example:
f("James")
should output as:
J-a-m-e-s-
I would love it if you could use simple python functions as I am new to programming. Thanks in advance. Also, please use the "for" function because it is what I'm trying to learn.
Edit:
yes, I do want the "-" after the "s".
Can I try like this:
>>> def f(n):
... return '-'.join(n)
...
>>> f('james')
'j-a-m-e-s'
>>>
Not really sure if you require the last 'hyphen'.
Edit:
Even if you want suffixed '-', then can do like
def f(n):
return '-'.join(n) + '-'
As being learner, it is important to understand for your that "better to concat more than two strings in python" would be using str.join(iterable), whereas + operator is fine to append one string with another.
Please read following posts to explore further:
Any reason not to use + to concatenate two strings?
which is better to concat string in python?
How slow is Python's string concatenation vs. str.join?
Also, please use the "for" function because it is what I'm trying to learn
>>> def f(s):
m = s[0]
for i in s[1:]:
m += '-' + i
return m
>>> f("James")
'J-a-m-e-s'
m = s[0] character at the index 0 is assigned to the variable m
for i in s[1:]: iterate from the second character and
m += '-' + i append - + char to the variable m
Finally return the value of variable m
If you want - at the last then you could do like this.
>>> def f(s):
m = ""
for i in s:
m += i + '-'
return m
>>> f("James")
'J-a-m-e-s-'
text_list = [c+"-" for c in text]
text_strung = "".join(text_list)
As a function, takes a string as input.
def dashify(input):
output = ""
for ch in input:
output = output + ch + "-"
return output
Given you asked for a solution that uses for and a final -, simply iterate over the message and add the character and '-' to an intermediate list, then join it up. This avoids the use of string concatenations:
>>> def f(message)
l = []
for c in message:
l.append(c)
l.append('-')
return "".join(l)
>>> print(f('James'))
J-a-m-e-s-
I'm sorry, but I just have to take Alexander Ravikovich's answer a step further:
f = lambda text: "".join([c+"-" for c in text])
print(f('James')) # J-a-m-e-s-
It is never too early to learn about list comprehension.
"".join(a_list) is self-explanatory: glueing elements of a list together with a string (empty string in this example).
lambda... well that's just a way to define a function in a line. Think
square = lambda x: x**2
square(2) # returns 4
square(3) # returns 9
Python is fun, it's not {enter-a-boring-programming-language-here}.

Categories

Resources