Python Memory Error for a capitalize function - python

I am new to python and want to write a function that takes in a string and returns a list of all possible capitalizations of the string. here it is:
def transform_capitalize(st):
l=[]
l.append(st.lower())
newl=l
length=len(st)
for x in range(0,length):
for i in l:
newl.append(i[:x]+i[x].upper()+i[(x+1):])
l=newl
return l
The logic is as follows:
Take the string and convert to lower cast then put into a list
then have a loop within a loop get the possibilities of each letter being uppercase one at a time and update the list after each letter position.
So for Foo as an example
l=['foo'] and length is 3 so from 0 to 2 take every element in the list and capitalize the letter in the ith position, append these to the newl, then update the list after all capitalizations at that position have been made
so when i = 0 the list should be ["foo","Foo"] at the end.
For i = 1 it should be ["foo","Foo""fOo","FOo"] and for 2 it should be ['foo', 'Foo', 'fOo', 'FOo', 'foO', 'FoO', 'fOO', 'FOO']. The order doesn't matter, but more some reason I'm getting a memory error so I'm assuming its some infinite loop.
Can anyone tell me whats wrong?

These 2 lines are the problem:
newl=l
l = newl
When you assign a variable an array, the default behavior is for the variable to act as a reference, not a copy. It means, if you assign a an empty list , then you assign a to b, appending anything to b or a is one and same.
a = []
b = a
b.append("hello")
print(a) # prints ["hello"]
To copy an array in python, you use slicing:
a = []
b = a[:] #here
b.append("hello")
print(a) # prints []
Now, changing reference assignment to copying when intended:
def transform_capitalize(st):
l=[]
l.append(st.lower())
newl=l[:]
length=len(st)
for x in range(0,length):
for i in l:
newl.append(i[:x]+i[x].upper()+i[(x+1):])
l=newl[:]
return l
transform_capitalize("hello"); #['hello', 'Hello', 'hEllo', 'HEllo', 'heLlo', 'HeLlo', 'hELlo', 'HELlo', 'helLo', 'HelLo', 'hElLo', 'HElLo', 'heLLo', 'HeLLo', 'hELLo', 'HELLo', 'hellO', 'HellO', 'hEllO', 'HEllO', 'heLlO', 'HeLlO', 'hELlO', 'HELlO', 'helLO', 'HelLO', 'hElLO', 'HElLO', 'heLLO', 'HeLLO', 'hELLO', 'HELLO']

A recursive solution could also be used:
def transform_capitalize(st):
result = []
if len(st) > 0:
head = st[0]
tails = transform_capitalize(st[1:])
for t in tails:
result.append( head.lower() + t )
result.append( head.upper() + t )
else:
result = [ '' ]
return result
Given an empty string, it will return a single empty string. It could be modified if this is not what we want (by placing the stop condition at length 1 instead of 0).

I'm bored, so here is a "Batteries Included" version of your function:
from itertools import product
from string import upper, lower
def capitalize(word):
word = word.lower()
for p in product([upper, lower], repeat=len(word)):
yield ''.join(fn(letter) for fn, letter in zip(p, word))
if __name__=='__main__':
print list(capitalize('foo'))

Related

How to count occurrences of a list of string inside of a list in python?

For example my list is
lst=['hello','world','this','is','hello','world','world','hello']
subString=['hello','world']
The result I'm looking for is in this case is 2 since the list ['hello','world'] occurs twice with that same order.
I tried doing
list(filter(lambda x : x in substring,lst))
but that returns all of hello and world
You could use " ".join() on both lists to create a string and then use str.count() to count the number of occurrences of subString in lst
lst=['hello','world','this','is','hello','world','world','hello']
subString=['hello','world']
l = " ".join(lst)
s = " ".join(subString)
count = l.count(s)
print("Joined list:", l)
print("Joined substring:", s)
print("occurrences:", count)
outputs:
Joined list: hello world this is hello world world hello
Joined substring: hello world
occurrences: 2
Using the window generator from this answer and a Counter, this can be expressed as:
from collections import Counter
lst=['hello','world','this','is','hello','world','world','hello']
subString=('hello','world')
counts = Counter(window(lst, len(subString)))
print(counts[subString])
# 2
If you want to skip the Counter, you could do
print(sum(x == subString for x in window(lst, len(subString))))
You can join the elements into a list of lists and then filter by those that match your substring array.
joinedWords = [lst[n:n + len(subString)] for n in range(0, len(lst), len(subString))]
# => [['hello', 'world'], ['this', 'is'], ['hello', 'world'], ['world', 'hello']]
filtered = list(filter(lambda x: x == subString, joinedWords))
print(len(filtered)) # 2
Since all elements are string in this case, I'd create a string from each list, then count the occurrences of the second string in the first string:
lst=['hello','world','this','is','hello','world','world','hello']
subString = ['hello','world']
s = ' '.join(lst)
subs = ' '.join(subString)
print(s.count(subs))

How to print this pattern using Tuples?

I am new to Python Tuples, and doing a learning exercise on the same. How should I print the following pattern when the input is the String HI,HELLO,WELCOME.
(('HI', 'HELLO', 'WELCOME'),)
((('HI', 'HELLO', 'WELCOME'),),)
(((('HI', 'HELLO', 'WELCOME'),),),)
My Attempt
n = input()
arr = tuple(raw_input().split())
arr1 = list()
print arr
while(n>0) :
print(tuple(arr,))
n -= 1
just define (or create) a tuple at start, then nest it on itself (reusing the same variable):
n = 3
arr = ('HI','HELLO','WELCOME') # or tuple(raw_input().split())
while(n>0):
arr = (arr,) # that's enough to create a tuple inside the tuple
print(arr)
n -= 1
result:
(('HI', 'HELLO', 'WELCOME'),)
((('HI', 'HELLO', 'WELCOME'),),)
(((('HI', 'HELLO', 'WELCOME'),),),)
Just nest your first tuple in another tuple each iteration.
>>> n = 3
>>> tup = ('HI', 'HELLO', 'WELCOME')
>>> for _ in range(n):
tup = tup,
print(tup)
(('HI', 'HELLO', 'WELCOME'),)
((('HI', 'HELLO', 'WELCOME'),),)
(((('HI', 'HELLO', 'WELCOME'),),),)
>>>
As you can see, on each iteration the tuple is nested a level deeper. The problem with your original method is that you didn't reassign the new nested tuple back to arr, so your tuple's never nested.
In your attempt you were always printing the same thing. You need to update the tuple on each iteration, so you have to have
while n>0:
arr = (arr,)
print(arr)
n=-1

Random shuffle each 2 letters in a word

Its possible to shuffle a word each two characters in a randomic way?
Like hello world changed to ehllo owlrd or hello wolrd or ehll owolrd.
I cant get something like the following results: olleh dlrow and lleho wodlr
Yes, put your string in some mutable data structure, like a list. Then a straightforward algorithm would be to iterate by two, starting at the second item, and randomly swap:
>>> def shuffle_by_two(word):
... wordl = list(word)
... for i in range(1, len(word), 2):
... if random.randint(0, 1):
... wordl[i-1], wordl[i] = wordl[i], wordl[i-1]
... return ''.join(wordl)
...
So, for example:
>>> shuffle_by_two("hello world")
'hello wolrd'
>>> shuffle_by_two("hello world")
'hello wolrd'
>>> shuffle_by_two("hello world")
'ehllo owrld'
>>> shuffle_by_two("hello world")
'ehllo world'
>>> shuffle_by_two("hello world")
'hello owlrd'
>>> shuffle_by_two("hello world")
'ehll oowrld'
>>>
Code
Break up the pairs of twos, sample, and recombine:
from random import sample
s = 'hello world'
twos = [s[i:i+2] for i in range(0, len(s), 2)] # Step 1
twos = ''.join([''.join(sample(two, len(two))) for two in twos]) # Step 2
print(twos)
ehll oowrld
Walkthrough
Step 1 uses list comprehension, basically a condensed for-loop. Specifying
range(0, len(s), 2) iterates over an object with a step size of 2. The best
way to easily visualize is to set i equal to its progressive values:
s[0:0+2] will give you 'he', and so on. The result of Step 1 is
['he', 'll', 'o ', 'wo', 'rl', 'd'].
The inner part of Step 2 also uses list comprehension to iterate over each of
the pairs established in Step 1. for two in twos says to perform the action
for each element in the list twos established in the previous step. You could replace each instance of two with any word that you like, such as pair (just don't use a keyword). Then using ''.join() concatenates the broken-up strings back together.
Note: this treats spaces as characters to involve in the shuffling.

Python: how to find out the occurrences of a sentence in a list

I'm writing a function to implement the solution to finding the number of times a word occurs in a list of elements, retrieved from a text file which is pretty straightforward to achieve.
However, I have been at it for two days trying to figure out how to check occurrences of a string which contains multiple words, can be two or more
So for example say the string is:
"hello bye"
and the list is:
["car", "hello","bye" ,"hello"]
The function should return the value 1 because the elements "hello" and "bye" only occur once consecutively.
The closest I've gotten to the solution is using
words[0:2] = [' '.join(words[0:2])]
which would join two elements together given the index. This however is wrong as the input given will be the element itself rather than an index.
Can someone point me to the right direction?
Two possibilities.
## laboriously
lookFor = 'hello bye'
words = ["car", "hello","bye" ,"hello", 'tax', 'hello', 'horn', 'hello', 'bye']
strungOutWords = ' '.join(words)
count = 0
p = 0
while True:
q = strungOutWords [p:].find(lookFor)
if q == -1:
break
else:
p = p + q + 1
count += 1
print (count)
## using a regex
import re
print (len(re.compile(lookFor).findall(strungOutWords)))
Match the string with the join of the consecutive elements in the main list. Below is the sample code:
my_list = ["car", "hello","bye" ,"hello"]
sentence = "hello bye"
word_count = len(sentence.split())
c = 0
for i in range(len(my_list) - word_count + 1):
if sentence == ' '.join(my_list[i:i+word_count]):
c+=1
Final value hold by c will be:
>>> c
1
If you are looking for a one-liner, you may use zip and sum as:
>>> my_list = ["car", "hello","bye" ,"hello"]
>>> sentence = "hello bye"
>>> words = sentence.split()
>>> sum(1 for i in zip(*[my_list[j:] for j in range(len(words))]) if list(i) == words)
1
Let's split this problem in two parts. First, we establish a function that will return ngrams of a given list, that is sublists of n consecutive elements:
def ngrams(l, n):
return list(zip(*[l[i:] for i in range(n)]))
We can now get 2, 3 or 4-grams easily:
>>> ngrams(["car", "hello","bye" ,"hello"], 2)
[('car', 'hello'), ('hello', 'bye'), ('bye', 'hello')]
>>> ngrams(["car", "hello","bye" ,"hello"], 3)
[('car', 'hello', 'bye'), ('hello', 'bye', 'hello')]
>>> ngrams(["car", "hello","bye" ,"hello"], 4)
[('car', 'hello', 'bye', 'hello')]
Each item is made into a tuple.
Now make the phrase 'hello bye' into a tuple:
>>> as_tuple = tuple('hello bye'.split())
>>> as_tuple
('hello', 'bye')
>>> len(as_tuple)
2
Since this has 2 words, we need to generate bigrams from the sentence, and count the number of matching bigrams. We can generalize all this to
def ngrams(l, n):
return list(zip(*[l[i:] for i in range(n)]))
def count_occurrences(sentence, phrase):
phrase_as_tuple = tuple(phrase.split())
sentence_ngrams = ngrams(sentence, len(phrase_as_tuple))
return sentence_ngrams.count(phrase_as_tuple)
print(count_occurrences(["car", "hello","bye" ,"hello"], 'hello bye'))
# prints 1
I would suggest reducing the problem into counting occurrences of a string within another string.
words = ["hello", "bye", "hello", "car", "hello ", "bye me", "hello", "carpet", "shoplifter"]
sentence = "hello bye"
my_text = " %s " % " ".join([item for sublist in [x.split() for x in words] for item in sublist])
def count(sentence):
my_sentence = " %s " % " ".join(sentence.split())
return my_text.count(my_sentence)
print count("hello bye")
>>> 2
print count("pet shop")
>>> 0

Retrieve first word in list index python

I want to know how to retrieve the first word at list index.
For example, if the list is:
['hello world', 'how are you']
Is there a way to get x = "hello how"?
Here is what I've tried so far (newfriend is the list):
x=""
for values in newfriend:
values = values.split()
values = ''.join(values.split(' ', 1)[0])
x+=" ".join(values)
x+="\n"
A simple generator expression would do, I guess, e.g.
>>> l = ["hello world", "how are you"]
>>> ' '.join(x.split()[0] for x in l)
'hello how'
You're not far off. Here is how I would do it.
# Python 3
newfriend = ['hello world', 'how are you']
x = [] # Create x as an empty list, rather than an empty string.
for v in newfriend:
x.append(v.split(' ')[0]) # Append first word of each phrase to the list.
y = ' '.join(x) # Join the list.
print(y)
import re
#where l =["Hello world","hi world"]
g=[]
for i in range(l):
x=re.findall(r'\w+',l[i])
g.append(x)
print(g[0][0]+g[1][0])

Categories

Resources