"Terminated due to timeout" status - Hackerank - python

Consider an array of numeric strings where each string is a positive
number with anywhere from 1 to 106 digits. Sort the array's elements in
non-decreasing, or ascending order of their integer values and return
the sorted array.
Example
Return the array ['1', '3', '150', '200'].
My code gets terminated due to timeout, How can I correct it?
#!/bin/python3
import math
import os
import random
import re
import sys
#
# Complete the 'bigSorting' function below.
#
# The function is expected to return a STRING_ARRAY.
# The function accepts STRING_ARRAY unsorted as parameter.
#
def bigSorting(unsorted):
unsorted = map(int,unsorted)
unsorted =sorted(unsorted)
unsorted = map(str, unsorted)
return unsorted;
if __name__ == '__main__':
fptr = open(os.environ['OUTPUT_PATH'], 'w')
n = int(input().strip())
unsorted = []
for _ in range(n):
unsorted_item = input()
unsorted.append(unsorted_item)
result = bigSorting(unsorted)
fptr.write('\n'.join(result))
fptr.write('\n')
fptr.close()
i tried reducing code, but it still says like that
its reduced the time but still say not enough.

You don't need to convert to and from int. You can sort numeric strings by first sorting by length, then sorting strings with equal length lexicographically (as long as there are no leading zeroes).
def bigsorting(unsorted):
return sorted(unsorted, key = lambda x: (len(x), x))

Related

Sorting strings in Python with numbers somewhere in the middle

I want to find a way to sort strings that have numbers in them by their numerical size.
I found one way to sort strings that contain only numbers, which works well (Sorting numbers in string format with Python) but not when the string is a mix of words and numbers.
In this example I am creating the list in the order that I want, but the sorted() ruins it.
>>> s = ['A_10x05', 'A_10x50', 'A_10x100']
>>> print(sorted(s))
['A_10x05', 'A_10x100', 'A_10x50']
Expected output
['A_10x05', 'A_10x50', 'A_10x100']
A more complex example would be:
>>> s = ['Asset_Castle_Wall_25x400x100_Bottom_01', 'Asset_Castle_Wall_25x400x50_Top_02',
'Asset_Castle_Wall_25x400x10_Bottom_01', 'Asset_Castle_Wall_25x400x300_Top_01']
>>> print(sorted(s))
['Asset_Castle_Wall_25x400x100_Bottom_01', 'Asset_Castle_Wall_25x400x10_Bottom_01', 'Asset_Castle_Wall_25x400x300_Top_01', 'Asset_Castle_Wall_25x400x50_Top_02']
Expected output:
['Asset_Castle_Wall_25x400x10_Bottom_01', 'Asset_Castle_Wall_25x400x50_Top_02', 'Asset_Castle_Wall_25x400x100_Bottom_01', 'Asset_Castle_Wall_25x400x300_Top_01']
I am thinking I would need to split the string by numbers and sort each part, and I can sort the number parts using the solution above. Then where there are multiple strings that start the same way i.e section[i] = ('A_') I sort section[i+1] and work my way to the end. This feels very complicated though, so maybe there is a better way.
IIUC, you are trying to multiply the numbers in 10x05 - which you can do by passing a key function to sorted
def eval_result(s):
prefix, op = s.split('_')
num1, num2 = map(int, op.split('x'))
return num1 * num2
sorted(s, key=eval_result)
Output
['A_10x05', 'A_10x50', 'A_10x100']
I believe what you want is just to sort each part of the input strings separately - text parts alphabetically, numeric parts by numeric value, with no multiplications involved. If this is the case you will need a helper function:
from re import findall
s = ['A_10x5', 'Item_A_10x05x200_Base_01', 'A_10x100', 'B']
def fun(s):
f = findall(r'\d+|[A-Za-z_]+',s)
return list(map(lambda x:int(x) if x.isdigit() else x, f))
sorted(s, key = fun)
['A_10x5', 'A_10x100', 'B', 'Item_A_10x05x200_Base_01']
Providing each string in the list contains exactly three dimensions:
import re
from functools import cache
s = ['Asset_Castle_Wall_25x400x100_Bottom_01', 'Asset_Castle_Wall_25x400x50_Top_02',
'Asset_Castle_Wall_25x400x10_Bottom_01', 'Asset_Castle_Wall_25x400x300_Top_01']
#cache
def get_size(s):
if len(tokens := s.split('x')) != 3:
return 0
first = re.findall('(\d+)', tokens[0])[-1]
last = re.findall('(\d+)', tokens[-1])[0]
return int(first) * int(tokens[1]) * int(last)
print(sorted(s, key=get_size))
Output:
['Asset_Castle_Wall_25x400x10_Bottom_01', 'Asset_Castle_Wall_25x400x50_Top_02', 'Asset_Castle_Wall_25x400x100_Bottom_01', 'Asset_Castle_Wall_25x400x300_Top_01']

Python rearrange a list without changing the values and making every rearrangment different

I want to write a function that get two integers. The integers indicate how many strings of either of the two chars appears in a string.
For example:
my_func(x,y): x amount of 'u' and y amount of 'r'.
my_func(2,3) is a string 'uurrr'
And the goal of the function is to write all the possible combinations of that string without changing the amount of x,y and every rearrangement is different:
Example:
my_func(1,1) will return: 'ru', 'ur'
my_func(1,2) will return: 'urr', 'rur', 'rru'
my_func(2,2) will return: 'uurr', 'ruru', 'rruu','urur', 'ruur', 'urru'
What I tried without covering all cases:
RIGHT = 'r'
UP = 'u'
def factorial(m):
if m>1:
return factorial(m-1)*m
else:
return 1
def binom(n,k):
return int(factorial(n)/(factorial(k)*factorial(n-k)))
def up_and_right(n, k, lst):
if n-k == 1 or n-k==-1 or n-k == 0 or n==1 or k==1:
num_of_ver = n+k
else:
num_of_ver = binom(n+k,2)
first_way_to_target = RIGHT*n + UP*k
lst.append(first_way_to_target)
way_to_target = first_way_to_target
for i in range(num_of_ver-1):
for j in range(n+k-1,0,-1):
if way_to_target[j]==UP and way_to_target[j-1]==RIGHT:
way_to_target = list(way_to_target)
way_to_target[j-1] = UP
way_to_target[j] = RIGHT
way_to_target = ''.join(way_to_target)
lst.append(way_to_target)
return lst
Thanks in advance!
Use itertools.permutations to get all the rearrangements, make a set of them to eliminate duplicates (because e.g. swapping two rs around counts as a separate permutation but doesn't change anything), and then join them back into strings because permutations returns character tuples instead.
This demonstration at the REPL should give you enough to write your function:
>>> import itertools
>>> [''.join(p) for p in set(itertools.permutations('u' * 2 + 'r' * 2))]
['uurr', 'ruur', 'ruru', 'rruu', 'urur', 'urru']

String index out of range in filter function

I'm trying to filter an array of binary numbers in string format, such as this ['01100', '11001'] where all of them are the same length. I'm filtering on the condition that the numbers on the position i must match the number on the position i from a list of binary integers such as [1, 0, 1, 0, 1].
This is what I tried:
def name(data, gamma):
res = data
for i in range(0, len(gamma)):
res = list(filter(lambda x: int(x[i]) == gamma[i], res))
return list(res)
where data is the list of binary string and gamma is the list of binary integers.
It throws a IndexError: string index out of range even tough this works just fine:
def get_O2(data, gamma):
res = data
for i in range(0, len(gamma)):
print(int(data[0][i]) == gamma[i])
return list(res)
Note that your function name loops with an index i in range(len(gamma)), but index i is used as an index both for gamma and for x, where x is an element of res. So, you are going to get an index out of range error if one of the strings in data is too short. For instance:
name(['01'], [1,0,1,0,1])
will produce the error.
Even worse, sometimes you won't get an error, but the result will be wrong:
print( name(['1010167'], [1,0,1,0,1]) )
# ['1010167']
Here the string '1010167' should have been filtered out, but it wasn't, because its first five characters match gamma.
A simple way to fix that problem is to test that the length of x is equal to the length of gamma before testing the equality of the bits. For instance you could add a first filter before the for-loop, and filter out all the strings that don't have the appropriate length:
def name(data, gamma):
res = list(filter(lambda x: len(x) == len(gamma), data))
for i in range(0, len(gamma)):
res = list(filter(lambda x: int(x[i]) == gamma[i], res))
return list(res)
print( name(['01100', '10101', '11001', '01', '010101010101010'], [1,0,1,0,1]) )
# ['10101']
However, I think it is cleaner to use a single filter, and have this filter check everything at once.
Because the function in filter is going to be a bit more complicated, I suggest using a def rather than a lambda:
def string_matches_intlist(x, gamma):
return len(x) == len(gamma) and all(int(c) == b for c,b in zip(x, gamma))
def name(data, gamma):
return list(filter(lambda x: string_matches_intlist(x,gamma), data))
print( name(['01100', '10101', '11001', '10101', '01', '010101010101010'], [1,0,1,0,1]) )
# ['10101', '10101']
I used two builtin functions to help me write string_matches_intlist:
all, to check that all elements of a sequence satisfy a property;
zip, to iterate on two sequences simultaneously.

How to replace x to a random number

If someone could help me make a minor script I would be more than happy, GGI20-xxxxxxx output should be GGI20-2562626 for example
Just change the digits according to number of xxxx's
import random
string = 'GGI20-xxxxxxx'
random_number = random.randint(1000000, 9999999)
result = string.replace("xxxxxxx", str(random_number))
print(result)
# OUTPUT
# GGI20-6187815
# GGI20-5790829
I suppose you need to replace all the x's in a string with a random number:
import random
def replaceXs(s):
result = ''
for c in s:
if c == 'x':
result += str(random.randrange(0, 10))
else:
result += c
return result
Why not just use the random library to generate a random integer with the right number of digits?
import random
def random_GGI20():
result = f'GGI20-{random.randint(1000000, 9999999)}'
return result
random_GGI20()
random_GGI20()
random_GGI20()
Note: this solution works if it's allowable to reuse numbers. If the GGI20-xxxxxxx results must be unique, this is more complex.
Here is a possible answer for your problem
input_string = 'GGI20-xxxxxxx'
import random
def replace_val(input_str):
str_list = list(input_str)
str_list = [str(i).replace('x',str(random.randint(0,9))) for i in str_list]
return ''.join(str_list)
replace_val(input_string)
o/p : 'GGI20-3428855' (it will vary as result will be random)
`
You could generate a random number using random(), convert to a string, and then replace however many x's your input has with an appropriate substring of the digits in the random number string.
inp = "GGI20-xxxxxxx"
output = re.sub(r'\bx+', lambda x: str(random())[2:len(x.group(0)) + 1], inp)
print(output) # GGI20-966494
import random
def random_gen():
return f"GGI20-{random.randint(1000000, 9999999)}"
print(random_gen())
this is much simple to understand
import random
#text type=string
text="GGI20-xxxxxxx"
#convert string into list to perform required operation
text_list=list(text)
#do a loop till we replace all x with randome number
#note here index method return a error if x not found hence we used try except block
while True:
try:
#this index('x') method raise an error when all x are replaced
text_list[text_list.index('x')]=str(random.randint(0,10))
except:
#create temporary string s to save output in it
s=""
#convert list to string
s=s.join(text_list)
break #break is important for finite looping
print("input text :"+text)
#save output result into main text variable
text=s
print("final output :"+text)
print("done")

Limiting size of list

How to ensure that a list has a certain number of elements only, and extra inputs after that are ignored?
import random
diceboard = [1,2,0,4,5,0] #for example
n=0
def roll():
dice1=random.randint(1,6)
dice2=random.randint(1,6)
dice3=random.randint(1,6)
dice4=random.randint(1,6)
dice5=random.randint(1,6)
dice6=random.randint(1,6)
return [dice1,dice2,dice3,dice4,dice5,dice6]
while diceboard.index!=0: #this basically means that per each element
that does not have a value of zero(pls correct my code)
n=n+1
newroll=roll()
newroll=newroll.split(None, n)[:n] #this limits the size of the list
print(newroll)
This is an interpretation of what I understood from your question:
https://pyfiddle.io/fiddle/0893e2af-726d-4fb3-9155-d83ecc5bbd55/
import random
diceboard = [1,2,0,4,5,0] #for example
def roll():
return list(map(
lambda x: random.randint(1,6),
range(len(diceboard))
))
n=0
#this basically means that per each element
#that does not have a value of zero(pls correct my code)
non_zero_diceboard = [d for d in diceboard if d > 0]
for i in range(len(non_zero_diceboard)):
n=n+1
newroll=roll()
newroll=newroll[:n] #this limits the size of the list
print(newroll)

Categories