How can I optimize my Python code to run faster? [closed] - python

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 7 months ago.
The community reviewed whether to reopen this question 7 months ago and left it closed:
Original close reason(s) were not resolved
Improve this question
Define an element of a list of items to be a dominator if every element to its right (not just the one element that is immediately to its right) is strictly smaller than that element. Note how by this definition, the last item of the list is automatically a dominator. This function should count how many elements in items are dominators, and return that count. For example, the dominators of the list [42, 7, 12, 9, 13, 5] would be the elements 42, 13 and 5. The last element of the list is trivially a dominator, regardless of its value, since nothing greater follows it.
I am working on this practice problem and have a code that works, however it's quite slow. How can I best optimize this to run faster?
def count_dominators(items):
item_count = len(items)
count = 0
if item_count==0:
return count;
count+=1;
if item_count==1:
return count;
for i in range(0,len(items)-1):
flag=1
for j in range(i+1,len(items)):
if(items[j]>=items[i]):
flag=0;
break;
if(flag==1):
count+=1;
return count

import numpy as np
def count_dominators(items):
dominators = np.unique(np.maximum.accumulate(seq[::-1]))
return dominators.size, dominators
seq = [42, 7, 12, 9, 13, 5]
print(count_dominators(seq))
>>>(3, array([5, 13, 42]))

Iterating in reverse order will reduce this from a O(n²) to O(n) as you'll keep a running maximum as you go, without needing to rescan all trailing elements for each new element. So without relying on complex utilities you didn't write, you can just do:
def count_dominators(items):
max_so_far = float('-inf') # Smaller than any value to it's replaced immediately,
# identifying first element as dominator by definition
count = 0
for item in reversed(items): # Iterate in reverse order so we only need to know max
# so far to identify new dominators
if item > max_so_far:
max_so_far = item
count += 1
return count
If you want more magic to do less of the work yourself, Python's itertools module provides an accumulate function that can repeatedly perform an operation on elements as it goes, yielding the result so far. If you use max as the operation, then it generates a stream of numbers that changes only when you see a new dominator. Convert the result to a set or use itertools.groupby (which is roughly equivalent to the uniq command line utility when run without arguments, making it a cheap way to deduplicate adjacent duplicates) to dedupe, and the length of the set or the number of groups is the dominator count:
from itertools import accumulate, groupby
def count_dominators(items):
return sum(1 for _, _ in groupby(accumulate(reversed(items), max)))
or at the cost of a technically unnecessary, growing for each new dominator, set (likely faster, as itertools.groupby has more overhead than you might expect, and the number of elements collected after deduplication is likely small enough to be irrelevant):
from itertools import accumulate
def count_dominators(items):
return len(set(accumulate(reversed(items), max)))
You could replace the sum(1 for _, _ in (and the matching trailing parenthesis) with a more efficient recipe for counting elements in an iterator if you like (though it hardly matters unless the inputs are huge).

Assuming there are only positive numbers, you can run on a list from its end and mark the biggest number you've met. It will be O(n) complexity, instead of O(n^2) that you've suggested.
Something like that shall work:
def count_dominators(items):
count = 0
last_biggest = -1
for i in range(len(items)-1,-1,-1):
if items[i] > last_biggest:
last_biggest = items[i]
count += 1
return count

Related

how can I plan this sequence-1,2,2,3,4,4,5 [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 months ago.
Improve this question
I am fairly new to programming and I try to create the above mentioned sequence.
this problem is about having a strict length of elements which always progresses, this progression is inside the list by moving on the indexes. this strict length shifts from a set of indexes to the next one once all the indexes inside the strict length (not passing it's limits) are finished being scanned, and they are scanned in a format of "one after the other".
after all of that we come to the root of the problem:
once the strict length moves to another set, it starts from the last index that was previously, inside of the strict length but in the previous strict length.
the output of the root problem is the title of this post. I don't know how to solve the root problem.
this problem, involves "k" as an exponent of the strict length.
this is the script:
strarr = ["1","2","3","4","5","6","7","8","9","10"]
k = 2
n = 0
while True:
for i in range(k):
print(strarr[n])
n = n+1
print(strarr[n])
the output I got is:
1,2,3,3,4,5,5,6,7,7,8,9,9,10
and I don't know why I got such output, it doesn't seem logical.
As I can understand what you are looking for is to print the even numbers twice.
You can do the following without using a for loop by this way.
strarr = ["1","2","3","4","5","6","7","8","9","10"]
k = 2
n = 0
while (n<10):
if(int(strarr[n])%2 == 0):
print(strarr[n])
print(strarr[n])
elif(int(strarr[n])%2 != 0):
print(strarr[n])
n = n+1
The reason why your code gives that output is because,
for the 1st iteration it would print 1, 2, 3
2nd iteration it would print out 3 again as there is another print(stararr[n]) outside the for loop. That's the reason why you are getting the output you are getting.
strarr = ["1","2","3","4","5","6","7","8","9","10"]
k = 2
n = 0
while True:
for i in range(k):
print(strarr[n])
n = n+1
print(strarr[n])
The error that I think you're seeing has to do with the order that you print your output and update the index n. In the current, buggy code, you're printing first, then updating the value. This means that the second print outside of the inner loop prints using the next value of n, not the one you just used in the inner loop. The same index gets used a second time in the first pass of the inner loop the next time, but that's not the value you wanted to see repeated.
The solution to this issue is pretty simple. Rather than updating after you print, update before. You'll need to adjust the starting value of n, but that's no problem:
strarr = ["1","2","3","4","5","6","7","8","9","10"]
k = 2
n = -1 # change starting index
while True:
for i in range(k):
n = n+1 # and reorder the lines in the inner loop
print(strarr[n])
print(strarr[n])
That said, the two loop thing is a lot more awkward than anything I'd really recommend. If you just want to repeat the odd-indexed values in the loop, you can do that much more simply:
for index in range(len(strarr)):
print(strarr[index])
if index % 2 == 1:
print(strarr[index])
Or you can avoid directly needing to index at all, using enumerate to get the index and value of each element in the for statement itself. This is probably a more "Pythonic" way to solve the problem.
for index, value in enumerate(strarr):
print(value)
if index % 2 == 1:
print(value)

Write a Python program to create and print a list where the values are first N square of numbers [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 months ago.
Improve this question
My teacher gave me an exercise during the computing lesson in week 2:
Write a Python program to create and print a list where the values are first N square of numbers. You are REQUIRED to implement a function named printSquare() to take n where n is an positive integer.
I'mm trying to writing a function called printSquare().
for example, the expected output of printSquare(5) is [1, 4, 9, 16, 25].
def getList(num):
list=[]
for i in range(int(num)):
list.append(i)
return list
def printSquare(num):
wholeList = list(getList(num))
wholeList.pop(0)
wholeList.append(num)
tmp=[]
for i in wholeList:
x = wholeList[i]**2
tmp.append(x)
return tmp
printSquare(5)
I'm struggling in the following part, I don't know why the tmp.append(x) doesn't work.
for i in wholeList:
x = wholeList[i]**2
tmp.append(x)
return tmp
The second question is that is there any faster way to write this code.
There are couple of mistakes and lack of understanding in the code. Let me try and explain mistakes and lack of understanding i found.
you are using range(num) which will give you a list from 0 to num-1. Hence you do wholeList.pop(0) to remove 0 from the list and wholeList.append(num) to then add the last num in.
Instead of that, you can do
range(1,int(num)+1)
This will return you a list from 1 to number, solving both the issue, and not needing to pop and add extra number to list
secondly
for i in wholeList:
x = wholeList[i]**2
That is not how looping over list works
for i in wholeList:
Will return you the element of the list, not its index. Here you are assuming i is the index of elements in list. So wholeList[i]**2 is where your code fails, since you try to access elements at index position that does not exist.
If you want to get index position you have to do
for index, value in enumerate(wholeList):
This will return you the index, and the value associated with the index in the list.
I hope, all of that helped you understand things better. Here is a code that works
def getList(num):
list=[]
for i in range(1,int(num)+1):
list.append(i)
return list
def printSquare(num):
wholeList = getList(num)
tmp=[]
for i in wholeList:
tmp.append(i**2)
return tmp
printSquare(5)
If you look at the error message it states that IndexError: list index out of range meaning that the index isn't in the range of your list. What you could do is try to use the range function over the length of the list: for i in range(1, len(wholeList)), this ensures that the index is always within the range.
when you use for..in you are directly getting elements, not indexes. So to solve the problem write
for i in wholeList:
x = i**2
tmp.append(x)
return tmp
Also, you can write this way more clearly with list comprehensions (and it is a nice tool to have)
def get_list(n):
return [i**2 for i in range(1, n+1)]
You have made this far more complicated than it really is. You can (should) use a list comprehension thus:
def printSquare(n):
print([x*x for x in range(1, n+1)])
printSquare(5)
Output:
[1, 4, 9, 16, 25]
The i in the for loop is the value, not the index. You should either write x=i**2, or in the for loop you should specify it differently:
for i, value in enumerate(wholeList):
x = value**2
tmp.append(x)
The tmp list now includes the square values of the wholeList.
Also, you are not printing anything somewhere.

What is my Solution for the assign minions doing wrong?

EDIT: I know there are other solutions to this. My question is what am I doing wrong. Where is my logic simple. Nothing else.
Was solving the minions work assignment code in Python.
The question is the following
Write a function called solution(data, n) that takes in a list of less than 100 integers and a
number n, and returns that same list but with all of the numbers that occur more than n times
removed entirely. The returned list should retain the same ordering as the original list - you don't want to mix up those carefully planned shift rotations! For instance, if data was [5, 10,
15, 10, 7] and n was 1, solution(data, n) would return the list [5, 15, 7] because 10 occurs
twice, and thus was removed from the list entirely.
My code is the following
from collections import OrderedDict
def solution(data, n):
# Your code here
if(len(data)>=100):
return []
seen=OrderedDict()
s=[]
for i in data:
if i in seen:
seen[i]+=1
else:
seen[i]=1
for k in seen:
if(seen[k]<=n):
s.append(k)
return s
My logic was to use an ordered dict to keep track of the numbers and the number of times they show up. This way we could do the code in linear time instead of n^2 (by checking the count of every value in data). This worked for most cases but is failing in some. What am I missing? Is there some space constraint? Some overlooked case?

Python: sum of List (recursive function) with starting point p [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I got stuck by finding out how to build a recursive function
that sums the elements in a list form a specific starting point
to the end of the list.
for example when list a[1,2,3,4,5,6,7,8,9,10] and starting point is Index 5
I want to get the sum of 6+7+8+9+10.
For me it is quite difficult to understand the whole concept of recursive functions. Maybe you can help me to get a step further understanding the concept.
Many thanks in advance
Define a function that normally computes the sum recursively.
To compute sum of a subsequence of a list, use list slicing.
def recsum(num_list):
if len(num_list) == 0:
return 0
return num_list[0] + recsum(num_list[1:])
a = [1,2,3,4,5]
recsum(a)
>>> 15
# It means 1+2+3+4+5
recsum(a[1:])
>>> 14
# It means 2+3+4+5
recsum(a[2:4])
>>> 7
# It means 3+4
It's difficult to describe a recursive function in short. Please read the comments carefully.
my_recursive_function will take the list and the index from which I want to calculate the sum
If the index==list_length then I already traversed the list so in this case I shall return 0.
If I have not completed traversing the list then I shall take the value of that index call my_recursive_function again from the next index. This is where recursion starts.
Then return the sum of current index and value of next indices.
For recursion we should place the recursion braking condition at the first portion of the function.Otherwise it may run infinitely.
def my_recursive_sum(my_list, index):
list_length = len(my_list)
if index == list_length: # If i am next to the last element then return 0 and I won't go next and I shall go back
return 0
return my_list[index] + my_recursive_sum(my_list, index + 1) # value of current index+value of next indices.
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
result = my_recursive_sum(a, 3)
print(result)
this is how I interpreted the code delivered by Taohidul Islam:
might be right?
recursion

Count the number of occurrences of a given item in a (sorted) list?

I'm asked to create a method that returns the number of occurrences of a given item in a list. I know how to write code to find a specific item, but how can I code it to where it counts the number of occurrences of a random item.
For example if I have a list [4, 6 4, 3, 6, 4, 9] and I type something like
s1.count(4), it should return 3 or s1.count(6) should return 2.
I'm not allowed to use and built-in functions though.
In a recent assignment, I was asked to count the number of occurrences that sub string "ou" appeared in a given string, and I coded it
if len(astr) < 2:
return 0
else:
return (astr[:2] == "ou")+ count_pattern(astr[1:])
Would something like this work??
def count(self, item):
num=0
for i in self.s_list:
if i in self.s_list:
num[i] +=1
def __str__(self):
return str(self.s_list)
If this list is already sorted, the "most efficient" method -- in terms of Big-O -- would be to perform a binary search with a count-forward/count-backward if the value was found.
However, for an unsorted list as in the example, then the only way to count the occurrences is to go through each item in turn (or sort it first ;-). Here is some pseudo-code, note that it is simpler than the code presented in the original post (there is no if x in list or count[x]):
set count to 0
for each element in the list:
if the element is what we are looking for:
add one to count
Happy coding.
If I told you to count the number of fours in the following list, how would you do it?
1 4 2 4 3 8 2 1 4 2 4 9 7 4
You would start by remembering no fours yet, and add 1 for each element that equals 4. To traverse a list, you can use a for statement. Given an element of the list el, you can check whether it is four like this:
if el == 4:
# TODO: Add 1 to the counter here
In response to your edit:
You're currently testing if i in self.s_list:, which doesn't make any sense since i is an element of the list and therefore always present in it.
When adding to a number, you simply write num += 1. Brackets are only necessary if you want to access the values of a list or dictionary.
Also, don't forget to return num at the end of the function so that somebody calling it gets the result back.
Actually the most efficient method in terms of Big-O would be O(log n). #pst's method would result in O(log n + s) which could become linear if the array is made up of equal elements.
The way to achieve O(log n) would be to use 2 binary searches (which gives O(2log n), but we discard constants, so it is still O(log n)) that are modified to not have an equality test, therefore making all searches unsuccessful. However, on an unsuccessful search (low > high) we return low.
In the first search, if the middle is greater than your search term, recurse into the higher part of the array, else recurse into the lower part. In the second search, reverse the binary comparison.
The first search yields the right boundary of the equal element and the second search yields the left boundary. Simply subtract to get the amount of occurrences.
Based on algorithm described in Skiena.
This seems like a homework... anyways. Try list.count(item). That should do the job.
Third or fourth element here:
http://docs.python.org/tutorial/datastructures.html
Edit:
try something else like:
bukket = dict()
for elem in astr:
if elem not in bukket.keys():
bukket[elem] = 1
else:
bukket[elem] += 1
You can now get all the elements in the list with dict.keys() as list and the corresponding occurences with dict[key].
So you can test it:
import random
l = []
for i in range(0,200):
l.append(random.randint(0,20))
print l
l.sort()
print l
bukket = dict()
for elem in l:
if elem not in bukket.keys():
bukket[elem] = 1
else:
bukket[elem] += 1
print bukket

Categories

Resources