I want to tailor-make a thousand delimiter in Python. I am generating HTML and want to use as thousand separator. (It would look like: 1 000 000)
So far I have found the following way to add a , as a separator:
>>> '{0:,}'.format(1000000)
'1,000,000'
But I don't see to be able to use a similar construction to get another delimiter. '{0:|}'.format(1000000) for example does not work. Is there an easy way to use anything (i.e., ) as a thousand separator?
Well, you can always do this:
'{0:,}'.format(1000000).replace(',', '|')
Result: '1|000|000'
Here's a simple algorithm for the same. The previous version of it (ThSep two revisions back) didn't handle long separators like :
def ThSep(num, sep = ','):
num = int(num)
if not num:
return '0'
ret = ''
dig = 0
neg = False
if num < 0:
num = -num
neg = True
while num != 0:
dig += 1
ret += str(num % 10)
if (dig == 3) and (num / 10):
for ch in reversed(sep):
ret += ch
dig = 0
num /= 10
if neg:
ret += '-'
return ''.join(reversed(ret))
Call it with ThSep(1000000, ' ') or ThSep(1000000, '|') to get the result you want.
It's about 4 times slower than the first method, though, so you can try rewriting this as a C extension for production code. This is only if speed matters much. I converted 2 000 000 negative and positive numbers in half a minute for the test.
There is no built in way to do this, But you can use str.replace, if the number is the only present value
>>> '{0:,}'.format(1000000).replace(',','|')
'1|000|000'
This is mentioned in PEP 378
The proposal works well with floats, ints, and decimals. It also allows easy substitution for other separators. For example:
format(n, "6,d").replace(",", "_")
Related
I have been coding for around half a year in uni and have done some side projects. This is one of them and although my code works for integers, I would like to know how it could be optimised using less lines of code. Coding at uni has taught me how to create many programs but not really how to optimise code and so any further tips would be greatly appreciated! <3
num = int(1230124013502)
def rem(num):
"""
Rem function separates the thousands in an intiger and converts to
a string. Function takes one input (num) which must be of intiger
form. Rem converts to string with commas separating the thousands
"""
num = str(num)
l = len(num)
remain = l%3
sum = ''
if remain == 0:
remain = 3
new = num[remain:]
pre = num[:remain]
#print(pre,new,remain)
l_new = len(new)
zeros = []
for i in range(3,l_new+3,3):
j = i - 3
post = new[j:i] + ','
zeros.append(post)
for i in range(len(zeros)):
sum += zeros[i]
tot = pre + ',' + sum
endpoint = len(tot) - 1
tot = tot[0:endpoint]
if l < 4:
print(num)
return num
else:
print(tot)
return tot
rem(num)
Hope you all are doing well in these times.
here's my code:
def ab(n):
first = 0
last = -1
endprod = n[first] + n[last]
endprod2 = n[first+1] + n[last-1]
endprod3 = n[first+2] + n[last-2]
endprod4 = n[first+3] + n[last-3]
endprod5 = n[first+4] + n[last-4]
endprod100 = endprod[::-1] + endprod2[::-1] + endprod3[::-1]+ endprod4[::-1]+ endprod5[::-1]
return endprod100
I was able do to it, however mine isn't a loop. Is there a way to convert my code into a for loop. So, increment by 1 and decrement by 1.
Thanks,
Try this:
def ab(n):
result = ''
for j in range(len(n) // 2):
result += n[-j-1] + n[j]
if len(n) % 2 == 1:
result += n[len(n) // 2]
return result
You also need the part
if len(n) % 2 == 1:
result += n[len(n) // 2]
because your input string might have an odd number of characters
Examples:
>>> ab('0123456789')
'9081726354'
>>> ab('01234956789')
'90817263549'
If you want to reuse your original logic:
def ab(n):
result = ''
first = 0
last = -1
for j in range(len(n) // 2):
result += n[last-j] + n[first+j]
if len(n) % 2 == 1:
result += n[len(n) // 2]
return result
You could also recurse it:
def ab(s):
if len(s)>2:
return s[-1]+s[0]+ab(s[1:-1])
else:
return s
But the last part of Riccardo's answer fits your question more closely.
you need to split your string for your loop, means first you broke your string to half then build your string, you could use zip to iterate over multiple iteratable. something like this:
def ab(s):
out = ""
for v0,v1 in zip(s[:len(s)//2 -1 :-1], s[:len(s)//2 ]):
out += v0 + v1
return out
the better version you should write without loop.
like this:
out = "".join(map(lambda x: "".join(x), zip(s[:len(s)//2 -1 :-1], s[:len(s)//2 ])))
There are already a lot of good answers that are probably clearer, easier to read and much better suited for learning purposes than what I'm about to write. BUT... something I wanted to bring up (maybe just telling myself, because I tend to forget it) is that sometimes destroying the original argument can facilitate this sort of things.
In this case, you could keep "poping" left and right, shrinking your string until you exhaust it
def swap_destr(my_str):
result = ""
while len(my_str) > 1:
result += my_str[-1] # Last char
result += my_str[0] # First char
my_str = my_str[1:-1] # Shrink it!
return result + my_str # + my_str just in case there 1 char left
print(swap_destr("0123456789"))
print(swap_destr("123456789"))
# Outputs:
# 9081726354
# 918273645
This is also a good problem to see (and play with) recursion:
def swap_recur(my_str):
if len(my_str) <= 1:
return my_str
return my_str[-1] + my_str[0] + swap_recur(my_str[1:-1])
print(swap_recur("0123456789"))
print(swap_recur("123456789"))
# Outputs:
# 9081726354
# 918273645
I am trying to preprocess some tweets for an ML project where I am having troubles with two types of strings e.g.
str1 = "coooool" and str2 = "gooooaaaaaal".
After removing repeated characters, I would like to maintain the word in str1, i.e.
cleaned_str1 = "cool" while cleaned_str2 = "goal".
I tried a few approaches that I found but I couldn't get the right output. Could someone help me with this? Thank you in advance.
Use regular expressions:
re.sub(r"(\w)\1+(\w)\2+", r"\1\2", "goooaaaal") # -> goal
re.sub(r"(\w)\1+(\w)\2+", r"\1\2", "coooool") # -> cool
def removeDuplicates(S):
n = len(S)
j = 0
if (n < 2) :
return
for i in range(n):
if (S[j] != S[i]):
j += 1
S[j] = S[i]
j += 1
S = S[:j]
return S
This was taken directly from Geeks for Geeks.
There is no way for a program to intuitively know that "cool" needs two "o's" as in your example.
I want to reverse digits in a number in python. Here are my two implementations.
One: convert the number into string and reverse each char in it
number = 2376674032
number_s = str(number)
index = len(number_s) - 1
str_list = []
while index > -1:
str_list.append(number_s[index])
index -= 1
result = int("".join(str_list))
print(result)
Two: using simple mathematics
number = 2376674032
N = 0
K = number
R = number % 10
while K > 0:
N = N*10 + R
K = K // 10
R = K % 10
result = N
print(result)
As I'm pretty new to python programming, so could someone help me with the following questions:
with the first approach, will "".join(str_list) produce a new string with each list element? if so is a better way to concatenate strings in python(something similar to StringBuffer in java)
which of the implementations is better from performance perspective?
You can reverse a string using -1 as the step in a slice. So this works:
number = 2376674032
number_s = str(number)
reverse_s = number_s[::-1]
reversed = int(reverse_s)
you want to reverse a number …..input it as string format , and do this:
number="8374783246837"
revnumber=number[::-1]
Done
a = 1234
a = int("".join(reversed(str(a))))
This will give a = 4321
reversed functions returns an iterable object.
If we do :
a = list(reversed(str(a)))
it will return [“3”,”2″,”1″]. We have then joined it and converted into int.
To make the number an integer type, we have to use the int function, as below:
numbers=str(123456)
#or numbers="123456"
print((int(numbers[::-1])))
print((type(int(numbers[::-1]))))
output:
654321
<class 'int'>
We can do this in a single line as well using [::-1]
print(int(str(int(input()))[::-1]))
#here is my answer . you can do it using simple recursion
# count digits recursively
def reverse_digits(n):
# base case
if n == 0:
pass
#recursive case
else:
print(n%10,end='')
return reverse_digits(n//10)
# reverse 123
reverse_digits(123)
````````````````````````````````````````````````````
I recently coded a python solution using dictoionaries which got TLE verdict. The solution is exactly similar to a multiset solution in c++ which works. So, we are sure that the logic is correct, but the implementation is not upto the mark.
The problem description for understanding below code (http://codeforces.com/contest/714/problem/C):
For each number we need to get a string of 0s and 1s such that i'th digit is 0/1 if respective ith digit in number is even/odd.
We need to maintain the count of number that have the same mapping that is given by above described point.
Any hints/pointer to improve the performance of below code? It gave TLE (Time Limit Exceeded) for a large test case(http://codeforces.com/contest/714/submission/20594344).
from collections import defaultdict
def getPattern(s):
return ''.join(list(s.zfill(19)))
def getSPattern(s):
news = s.zfill(19)
patlist = [ '0' if (int(news[i])%2 == 0) else '1' for i in range(19) ]
return "".join(patlist)
t = int(raw_input())
pat = defaultdict(str) # holds strings as keys and int as value
for i in range(0, t):
oper, num = raw_input().strip().split(' ')
if oper == '+' :
pattern = getSPattern(str(num))
if pattern in pat:
pat[pattern] += 1
else:
pat[pattern] = 1
elif oper == '-' :
pattern = getSPattern(str(num))
pat[pattern] = max( pat[pattern] - 1, 0)
elif oper == '?' :
print pat.get(getPattern(num) , 0 )
I see lots of small problems with your code but can't say if they add up to significant performance issues:
You've set up, and used, your defaultdict() incorrectly:
pat = defaultdict(str)
...
if pattern in pat:
pat[pattern] += 1
else:
pat[pattern] = 1
The argument to the defaultdict() constructor should be the type of the values, not the keys. Once you've set up your defaultdict properly, you can simply do:
pat = defaultdict(int)
...
pat[pattern] += 1
As the value will now default to zero if the pattern isn't there already.
Since the specification says:
- ai — delete a single occurrence of non-negative integer ai from the multiset. It's guaranteed, that there is at least one ai in the
multiset.
Then this:
pat[pattern] = max( pat[pattern] - 1, 0)
can simply be this:
pat[pattern] -= 1
You're working with 19 character strings but since the specification says the numbers will be less than 10 ** 18, you can work with 18 character strings instead.
getSPattern() does a zfill() and then processes the string, it should do it in the reverse order, process the string and then zfill() it, as there's no need to run the logic on the leading zeros.
We don't need the overhead of int() to convert the characters to numbers:
(int(news[i])%2 == 0)
Consider using ord() instead as the ASCII values of the digits have the same parity as the digits themselves: ord('4') -> 52
And you don't need to loop over the indexes, you can simply loop over the characters.
Below is my rework of your code with the above changes, see if it still works (!) and gains you any performance:
from collections import defaultdict
def getPattern(string):
return string.zfill(18)
def getSPattern(string):
# pattern_list = (('0', '1')[ord(character) % 2] for character in string)
pattern_list = ('0' if ord(character) % 2 == 0 else '1' for character in string)
return ("".join(pattern_list)).zfill(18)
patterns = defaultdict(int) # holds keys as strings as and values as int
text = int(raw_input())
for _ in range(text):
operation, number = raw_input().strip().split()
if operation == '+':
pattern = getSPattern(number)
patterns[pattern] += 1
elif operation == '-':
pattern = getSPattern(number)
patterns[pattern] -= 1
elif operation == '?':
print patterns.get(getPattern(number), 0)
With the explanation already done by #cdlane, I just need to add my rewrite of getSPattern where I think the bulk of time is spent. As per my initial comment this is available on https://eval.in/641639
def getSPattern(s):
patlist = ['0' if c in ['0', '2', '4', '6', '8'] else '1' for c in s]
return "".join(patlist).zfill(19)
Using zfill(18) might marginally spare you some time.