Indexing function for a string in python - python

I am trying to implement a function called say "Function" from scratch that counts how many times each parameter z of letters occurs sequentially in a string.
For example, Function('abcbcb', z=2)
should return ab:1, bc:2, cb: 2
or Function('abcbcb', z=3) should return
abc: 1, bcb: 2, cbc: 1
I have tried using loops and python string methods but I have not been able to write a working one yet.
Thank you!

First let's call the function another name because this one is confusing. I'll call it times.
iterable[n:k] will return the iterable from index n (inclusive) to index k(exclusive).
here is a code with explanations:
def times(str, z):
dict ={} # we create an empty dict
for i in range(len(str)-z+1): #we loop over the string a number of times depending on z so we can check all z length paramters
if str[i:i+z] in dict.keys(): #if the part of the string is in the keys of the dictionary then we add one
dict[str[i:i+z]] += 1
else:
dict[str[i:i+z]] = 1 # if it wasn't we set it to one
return dict
times('abcbcb',3)

Related

I need some help using a dictionary as a function parameter

I need to replicate this same function but instead of having a list as a parameter I need a dictionary. The idea is that the calculation done by the function is done with the values, and the function returns the keys.
def funcion(dic, Sum):
Subset = []
def f(dic, i, Sum):
if i >= len(dic): return 1 if Sum == 0 else 0
count = f(dic, i + 1, Sum)
count += f(dic, i + 1, Sum - dic[i])
return count
for i, x in enumerate(dic):
if f(dic, i + 1, Sum - x) > 0:
Subset.append(x)
Sum -= x
return Subset
The function works if I enter (300, 200,100,400). But i need to use as an input something like {1:300 , 2:200 , 3:100, 4:400 }
So the calculation is done with the values, but it returns the keys that match the condition.
Im trying working with dic.keys() and dic.values() but its not working. Could you help me?
Thank u so much.
Your code isn't working with your dictionary because it's expecting to be able to index into dic with numeric indexes starting at 0 and going up to len(dic)-1. However, you've given your dictionary keys that start at 1 and go to len(dic). That means you need to change things up.
The first change is in the recursive f function, where you need the base case to trigger on i > len(dic) rather than using the >= comparison.
The next change in in the loop that calls f. Rather than using enumerate, which will generate indexes starting at 0 (and pair them with the keys of the dictionary, which is what you get when you directly iterate on it), you probably want to do something else.
Now, ideally, you'd want to iterate on dic.items(), which would give you index, value pairs just like your code expects. But depending on how the dictionary gets built, that might iterate over the values in a different order than you expect. In recent versions of Python, dictionaries maintain the order their keys were added in, so if you're creating the dictionary with {1:300, 2:200, 3:100, 4:400 }, you'll get the right order, but a mostly-equivalent dictionary like {3:100, 4:400, 1:300, 2:200 } would give its results in a different order.
So if you need to be resilient against dictionaries that don't have their keys in the right order, you probably want to directly generate the 1-len(dict) keys yourself with range, and then index to get the x value inside the loop:
for i in range(1, len(dic)+1): # Generate the keys directly from a range
x = dic[i] # and do the indexing manually.
if f(dic, i + 1, Sum - x) > 0: # The rest of the loop is the same as before.
Subset.append(x)
Sum -= x

How to modify the list elements with using no returning function

Really sorry for my bad English first,
I made two functions to continually modify (actually remove one by one) the elements in the list and to show the last element in the end, but the removing function is not giving impact on the list that I want to modify.
I think this is a problem about local-variables and mutability of list, but I don't know how to fix it.
At first, I give a list as an argument of one of the functions that I made, removing function. Removing function removes the element until it has only one element USING THE OTHER FUNCTION. In that function, I put my other function(I'll call this checking function) in. Checking function checks the elements to remove, and 'actually' remove one element in my code, but returns nothing.
Please note x and y variable is random value in range of length of seq (I did not write this in my example code),
and they will be changed every time in while loop in removing function.
import random
def checking(x, y, seq):
positions = [x, y]
positions.sort()
if seq[x] == 'b' and seq[y] == 'b':
seq.pop(positions[1])
seq.pop(positions[0])
seq.append('a')
else:
seq.pop(positions[1])
seq.pop(positions[0])
seq.append('b')
def removing(seq):
while len(seq) != 1:
x, y = random1, random2
remove(x, y, list(seq))
return seq[0]
final(['a','a','b','a','b'])
I tested checking function is working well thus, I think this is problem of removing function.
I expected the list seq modified every time passing 'remove' function and finally return the last element, but there's nothing changed and stuck in infinite loop.
Thank you for reading my question.
list(seq) makes a new list instance where its items are shallow copies of seq items.
The while loop never terminates for this reason as the list never empties.
Pass the same seq to remove function instead of making a new list instance.
remove(x, y, seq)
When given argument is a tuple, convert it to a mutable list before going into the loop:
seqm = list(seq)
while len(seqm) != 1:
x, y = random1, random2
remove(x, y, seqm)
return seqm[0]

Custom Key for Sort Function Doesn't Work

Given an array A[] of integers, A has to be sorted according to frequency of elements. If frequencies of two elements are same, then smaller number comes first.
I've tried to solve the problem using the following code using the sort function but my custom key for the sort() does not seem to work. Can someone tell me what's going on here?
'''a is the input array and n is it's sizeQ'''
def sortByFreq(a,n):
def count(k):
return n-a.count(k)
a.sort(key=int)
a.sort(key=count)
a=list(map(str,a))
answer=' '.join(a)
print(answer)
For an input array [9,9,9,2,5], the code is supposed to print 9 9 9 2 5, (as the array already is), but it prints 2 5 9 9 9 instead. (The second time I call sort it does not seem to work)
The problem is that you just cannot use the original list inside a sort key, because sort uses an out of place location to compute the sort.
At some point, the original a is empty. Don't expect something like "all elements of a are in it" when calling the sort key.
In fact, if you print a in the count method, you'll get an empty list, everytime.
The workaround is to make a copy of the list and use it in the sort key (aside: no need to pass the size of the list, since len can compute that)
def sortByFreq(a):
def count(k):
return len(a_copy)-a_copy.count(k)
a_copy = a.copy() # create a copy of the list
a.sort(key=count)
a=list(map(str,a))
answer=' '.join(a)
print(answer)
an alternative is to pre-count elements with a counter (uses hashes, so faster). Note that you have to store the length of a too.
def sortByFreq(a):
def count(k):
return n-c[k]
c = collections.Counter(a)
n = len(a)
a.sort(key=count)
finally, a shorter way would use reverse=True to simplify sort key, which we can turn to a lambda:
def sortByFreq(a):
c = collections.Counter(a)
a.sort(key=lambda k:c[k],reverse=True)
def sort_by_frequency(sequence):
"""Sort sequence by frequency."""
return ''.join(sorted([char for char in sequence], key=sequence.count, reverse=True))
if __name__ == '__main__':
print(sort_by_frequency('92959'))

python - Length of a list with the reduce() function

I need some help to count the numbers of elements in a list by using the reduce function.
def lenReduce(L):
return reduce(lambda x: x + 1, L)
With this one I get the following error message:
TypeError: <lambda>() takes 1 positional argument but 2 were given
Greetings from Berlin. ;-)
lenReduce([5,3,1])
returns 7
What this means is, for the very first time when the lambda function is invoked, count is set to 5 and item is set to 3 which are the first two elemets of the list. From the next invocation of the lambda function, count is incremented. Therefore the solution does not work.
The solution is to set the count to a value of our choosing rather than the first element of the list. To do that, invoke reduce with three arguments.
def lenReduce(L):
return reduce(lambda count, item: count + 1, L, 0)
In the above call of reduce, count is set to 0 and item will be set to the elements of the list starting from index 0 on each iteration.
lenReduce([3,2,1])
outputs 3 which is the desired result.
The function argument to reduce takes two arguments: the return value of the previous call, and an item from the list.
def counter(count, item):
return count + 1
In this case, you don't really care what the value of item is; simply passing it to counter means you want to return the current value of the counter plus 1.
def lenReduce(L):
return reduce(counter, L)
or, using a lambda expression,
def lenReduce(L):
return reduce(lambda count, item: count + 1, L)
Even though your function ignores the second argument, reduce still expects to be able to pass it to the function, so it must be defined to take two arguments.
All previous answers seemed not work since it will add 1 to the first element of the given list every iteration. Try this trick, add 0 as the first element of the list, then decrease the return value by 1.
lenReduce = lambda L: reduce(lambda x, y: x+1, [0]+L, 0) - 1

Is "for x in range(3): print x" guaranteed to print "0, 1, 2" in that order?

Is a loop of the form
for x in range(3):
print x
guaranteed to output
0
1
2
in that order? In other words, if you loop over a list with a for item in mylist statement, is the loop guaranteed to start at mylist[0] and proceed sequentially (mylist[1], mylist[2], ...)?
Yes, the builtin list and range will always iterate in the order you expect. Classes define their own iteration sequence, so the iteration order will vary between different classes. Due to their nature set and dict (amongst others) won't iterate in a predictable order.
You can define any iteration sequence you want for a class. For example, you can make a list that will iterate in reverse.
class reversedlist(list):
def __iter__(self):
self.current = len(self)
return self
def next(self):
if self.current <= 0:
raise StopIteration
self.current -= 1
return self[self.current]
x = reversedlist([0, 1, 2, 3, 4, 5])
for i in x:
print i,
# Outputs 5 4 3 2 1 0
Yes it does. It is not the for loop that guarantees anything, but the range function though. range(3) gives you an iterator that returns 0, then 1 and then 2. Iterators can only be accessed one element at a time, so that is the only order the for loop can access the elements.
Other iterators (ones not generated by the range function for example) could return elements in other orders.
is the loop guaranteed to start at mylist[0] and proceed sequentially (mylist[1], mylist[2], ...)?
When you use a for loop, the list gets used as an iterator. That is, the for loop actually does not index into it. It just keeps calling the next function until there are no more elements. In this way the for loop itself has no say in what order elements gets processed.
Yes, it is.
A python for loop like this:
for e in list:
print e
can be traslated as:
iterator = list.__iter__()
while True:
try:
e = iterator.next()
except StopIteration:
break
print e
So, while the "next" method of the object iterator returns values in the "correct" order you will get the elements in the "correct" order.
For python list this is guaranteed to happen.
For more information look here and here
Yes. for loops in Python traverse a list or an iter in order. range returns a list in Python 2.x and an iterator in Python 3.x, so your for x in range(3) loop will indeed always be ordered.
However, the same cannot be said for dicts or sets. They will not be traversed in order - this is because the order of their keys is undefined.
Yes, it starts with the first element of a list and goes to the last.
Not all data types in python do that, such as dicts, but lists certainly do. range(x) certainly will.
Yes.
But with a dictionary thereĀ“s no order guaranteed.
Yes. Python docs about For Loop say:
Basically, any object with an iterable method can be used in a for loop in Python ... Having an iterable method basically means that the data can be presented in list form, where there's multiple values in an orderly fashion

Categories