generating a string representation of a list of tuples - python

I have a list of tuples of form
[("very", "ADJ"), ("slow", "ADJ"), ("programmer", "NOUN")]
My desired output is a single string of form:
"very/ADJ slow/ADJ programmer/NOUN"
This being python, I know I can do this in a one-liner using the format() and join() methods, but I can't get the syntax quite right. My most recent attempt was:
output_string = " ".join(["{0}/{1}".format(x) for x in list_of_tuples])
which threw an Index Error: tuple index out of range"

You want format(*x) so that the x tuple is expanded into arguments. Otherwise you are trying to call format with a single argument which is itself a tuple.
That said, if you know that these are all 2-tuples, I'd just go with the simpler:
output_string = " ".join(a + "/" + b for a, b in list_of_tuples)
Also note that there's no need to use a list comprehension to pass into join -- just use a generator comprehension instead.

words = [("very", "ADJ"), ("slow", "ADJ"), ("programmer", "NOUN")]
' '.join('/'.join((x,y)) for x,y in words)

You can use map too:
>>> ' '.join(map(lambda t: '{}/{}'.format(*t), li))
'very/ADJ slow/ADJ programmer/NOUN'
And, that same method without the lambda:
>>> ' '.join(map('/'.join, li))
'very/ADJ slow/ADJ programmer/NOUN'
Which works even if you have more than two elements in your tuples.

Related

How to perform in-place removal of duplicates from a string in Python?

I am trying to implement an inplace algorithm to remove duplicates from a string in Python.
str1 = "geeksforgeeks"
for i in range(len(str1)):
for j in range(i+1,len(str1)-1):
if str1[i] == str1[j]: //Error Line
str1 = str1[0:j]+""+str1[j+1:]
print str1
In the above code, I am trying to replace the duplicate character with whitespace. But I get IndexError: string index out of range at if str1[i] == str1[j]. Am I missing out on something or is it not the right way?
My expected output is: geksfor
You can do all of this with just a set and a comprehension. No need to complicate things.
str1 = "geeksforgeeks"
seen = set()
seen_add = seen.add
print(''.join(s for s in str1 if not (s in seen or seen_add(s))))
#geksfor
"Simple is better than complex."
~ See PEP20
Edit
While the above is more simple than your answer, it is the most performant way of removing duplicates from a collection the more simple solution would be to use:
from collections import OrderedDict
print("".join(OrderedDict.fromkeys(str1)))
It is impossible to modify strings in-place in Python, the same way that it's impossible to modify numbers in-place in Python.
a = "something"
b = 3
b += 1 # allocates a new integer, 4, and assigns it to b
a += " else" # allocates a new string, " else", concatenates it to `a` to produce "something else"
# then assigns it to a
As already pointed str is immutable, so in-place requirement make no sense.
If you want to get desired output I would do it following way:
str1 = 'geeksforgeeks'
out = ''.join([i for inx,i in enumerate(str1) if str1.index(i)==inx])
print(out) #prints: geksfor
Here I used enumerate function to get numerated (inx) letters and fact that .index method of str, returns lowest possible index of element therefore str1.index('e') for given string is 1, not 2, not 9 and not 10.
Here is a simplified version of unique_everseen from itertools recipes.
from itertools import filterfalse
def unique_everseen(iterable)
seen = set()
see _ add = seen.add
for element in filterfalse(seen.__contains__, iterable):
seen_add(element)
yield element
You can then use this generator with str.join to get the expected output.
str1 = "geeksforgeeks"
new_str1 = ''.join(unique_everseen(str1)) # 'geksfor'

Reverse strings in a nested list without slicing or reversed

In python if my list is
TheTextImage = [["111000"],["222999"]]
How would one loop through this list creating a new one of
NewTextImage = [["000111"],["999222"]]
Can use [:] but not [::-1], and cannot use reverse()
You know how to copy a sequence to another sequence one by one, right?
new_string = ''
for ch in old_string:
new_string = new_string + ch
If you want to copy the sequence in reverse, just add the new values onto the left instead of onto the right:
new_string = ''
for ch in old_string:
new_string = ch + new_string
That's really the only trick you need.
Now, this isn't super-efficient, because string concatenation takes quadratic time. You could solve this by using a collections.deque (which you can append to the left of in constant time) and then calling ''.join at the end. But I doubt your teacher is expecting that from you. Just do it the simple way.
Of course you have to loop over TextImage applying this to every string in every sublist in the list. That's probably what they're expecting you to use [:] for. But that's easy; it's just looping over lists.
You may not use [::-1] but you can multiply each range index by -1.
t = [["111000"],["222999"]]
def rev(x):
return "".join(x[(i+1)*-1] for i in range(len(x)))
>>> [[rev(x) for x in z] for z in t]
[['000111'], ['999222']]
If you may use the step arg in range, can do AChampions suggestion:
def rev(x):
return ''.join(x[i-1] for i in range(0, -len(x), -1))
If you can't use any standard functionality such as reversed or [::-1], you can use collections.deque and deque.appendleft in a loop. Then use a list comprehension to apply the logic to multiple items.
from collections import deque
L = [["111000"], ["222999"]]
def reverser(x):
out = deque()
for i in x:
out.appendleft(i)
return ''.join(out)
res = [[reverser(x[0])] for x in L]
print(res)
[['000111'], ['999222']]
Note you could use a list, but appending to the beginning of a list is inefficient.
You can use reduce(lambda x,y: y+x, string) to reverse a string
>>> from functools import reduce
>>> TheTextImage = [["111000"],["222999"]]
>>> [[reduce(lambda x,y: y+x, b) for b in a] for a in TheTextImage]
[['000111'], ['999222']]

Splitting lists at the commas

Currently I have a long list that has elements like this:
['01/01/2013 06:31, long string of characters,Unknown'].
How would I split each element into:
['01/01/2013 06:31], [long string of characters],[Unknown]? Can I even do that?
I tried variable.split(","), but I get "AttributeError: 'list' object has no attribute 'split'".
Here's my code:
def sentiment_analysis():
f = open('C:\path', 'r')
write_to_list = f.readlines()
write_to_list = map(lambda write_to_list: write_to_list.strip(), write_to_list)
[e.split(',') for e in write_to_list]
print write_to_list[0:2]
f.close()
return
I'm still not getting it, I'd appreciate any help!
Solution
You are given this:
['01/01/2013 06:31, long string of characters,Unknown']
Alright. If you know that there is only this one long string in this list, just extract the only element:
>>> x = ['01/01/2013 06:31, long string of characters,Unknown']
>>>
>>> y = x[0].split(",") # extract only element and split by comma
>>> print(y) # list of strings, with one depth
['01/01/2013 06:31', ' long string of characters', 'Unknown']
Now for whatever reasons, you actually want each eletent of the outer list to be a list with one string in it. That is easy enough to do - simply use map and anonymous functions:
... # continuation from snippet above
...
>>> z = map(lambda s: [s], y) # encapsulates each elem of y in a list
>>> print(z)
[['01/01/2013 06:31'], [' long string of characters'], ['Unknown']]
There you have it.
One-Liner Conclusion
No list comprehensions, no for loops, no generators. Just really simple functional programming and anonymous functions.
Given original list l,
res = map(lambda s: [s],
l[0].split(","))
List comprehension!
>>> variable = ['01/01/2013 06:31, long string of characters,Unknown']
>>> [x.split(',') for x in variable]
[['01/01/2013 06:31', ' long string of characters', 'Unknown']]
But wait, that's nested more than you wanted...
>>> itertools.chain.from_iterable(x.split(',') for x in variable)
<itertools.chain object at 0x109180fd0>
>>> list(itertools.chain.from_iterable(x.split(',') for x in variable))
['01/01/2013 06:31', ' long string of characters', 'Unknown']

How to print items within lists in a list

Hear me out, I do not simply want someone to solve this problem for me. I know it is not 100% complete yet, but currently when I run the program I get an error about "Can't convert 'list' object to str implicitly" I'm looking for help on how to fix this and why it is does this.
Here is the problem
Write code to print out each thing in the list of lists, L, with a '*' after it like
1*2*3*4*...8*a*b*c*d*
This requires knowing the print statement and using the end or sep argument option
Here is my list, sorry for not putting it in earlier
L = [[1,2,3,4],[5,6,7,8],['a','b','c','d']]
Here is my code at the moment
def ball(x): #random function name with one parameter
q = '' #
i = 0
if type(x) != list: #verifies input is a list
return"Error"
for i in x: #Looks at each variable in list
for j in i: #Goes into second layer of lists
q = q + j + '*'
print(q)
The reason for your error
"Can't convert 'list' object to str implicitly"
is that you're using the wrong variable in your nested for loops. Where you're concatenating values to your q variable, you mistakenly put q = q + i when you wanted q = q + j. You also will want to cast the value of j as a string so it can be concatenated with q. In order to get your desired output, you can simply add an asterisk into that statement - something like the following: q = q + str(j) + '*'. On a completely unrelated note, your else statement that just has "Mistake" in it should be removed completely - it doesn't follow an if and it doesn't actually return or assign to a variable.
Note that this is not the most elegant way to go about solving this problem. I agree with ilent2 that you should take a look at both list comprehension and the str.join() method.
If you have a list of strings,
myList = ['a', '123', 'another', 'and another']
You can join them using the str.join function:
Help on method_descriptor:
join(...)
S.join(iterable) -> string
Return a string which is the concatenation of the strings in the
iterable. The separator between elements is S.
myString = '#'.join(myList)
If your list contains mixed types or non-strings you need to convert each item to a string first:
anotherList = [1, 2, 'asdf', 'bwsg']
anotherString = '*'.join([str(s) for s in anotherList])
You might want to read about list comprehension or more about the join function. Note, the above doesn't print the output (unless you are using the interactive console), if you want the output to be printed you will need call print too
print myString
print anotherString
And, if you are working with lists-of-lists you may need to change how you convert each sub-list into a string (depending on your desired output):
myListList = [[1, 2, 3, 4], [2, 3, 6, 5], [6, 4, 3, 1]]
myOtherString = '#'.join(['*'.join([str(s) for s in a]) for a in myListList])
The last line is a little complicated to read, you might want to rewrite it as a nested for loop instead.

Adding same string string repeatedly to a list to make it a tuple

I'm trying to combine a string with a series of numbers as tuples to a list.
For example, starting with:
a = [12,23,45,67,89]
string = "John"
I want to turn that into:
tuples = [(12,'John'),(23,'John'),(45,'John'),(67,'John'),(89,'John')]
I tried:
string2 = string * len(a)
tuples = zip(a, string2)
but this returned:
tuples = [(12,'J'), (23,'o'), ...]
If you want to use zip(), then create a list for your string variable before multiplying:
string2 = [string] * len(a)
tuples = zip(a,string2)
string * len(a) creates one long string, and zip() then iterates over that to pull out individual characters. By multiplying a list instead, you get a list with len(a) separate references to the string value; iteration then gives you string each time.
You could also use itertools.repeat() to give you string repeatedly:
from itertools import repeat
tuples = zip(a, repeat(string))
This avoids creating a new list object, potentially quite large.
>>> a = [12,23,45,67,89]
>>> string = "John"
>>> my_tuple = [(i,string) for i in a]
>>> print my_tuple
You can iterate over each position within a string so zip causes the behavior you were seeing previously.

Categories