For example, 1 should give me alphabet a,
2 > b
3 > c
...
26 > a
And 27 should give an again
28 > b
.. Till 9999
The below code only works with 26 numbers
import string
di=dict(zip(string.letters,[ord(c)%32 for c in string.letters]))
di['c']
Output is 3.
Can anyone please help?
this would do
def num2char(num):
return chr(((num-1) % 26) + ord('a'))
you don't need to go through a dictionary to convert numbers to letters that way. You can apply the modulo to positions in a string of letters
letters = "abcdefghijklmnopqrstuvwxyz"
for i in range(1,1000):
print(i,">",letters[(i-1)%26])
output:
1 > a
2 > b
3 > c
4 > d
5 > e
6 > f
7 > g
8 > h
9 > i
10 > j
11 > k
12 > l
13 > m
14 > n
15 > o
16 > p
17 > q
18 > r
19 > s
20 > t
21 > u
22 > v
23 > w
24 > x
25 > y
26 > z
27 > a
28 > b
29 > c
...
See if either one of these is what you're looking for:
print (ord ('a') - 96)
print (chr (1 + 96))
Your data structure is odd. If your input alphabet contains 9999 symbols, you need a dictionary of that many elements. But actually you don't really need a dictionary at all, just the observation that the input number modulo 26 plus 1 maps to the character codes starting at a.
def strmap(numbers):
base = ord('a')
mapped = [chr(base + (n-1)%26) for n in numbers]
return ''.join(mapped)
Demo: https://ideone.com/FeVkO4
Related
I have 1296 random values ranging 0-31. I want to represent this information so let’s say I just concatenate all 1296 values into a string. If I were to do that the string would be about 2500 characters long. How can I store this information in a shorter string so I can still know all 1296 values in the correct order but not have such a long string? (I managed to get it to 648, but wanted to see if someone has an even better way)
This will work when the range of numbers in the input list are 0-31 (inclusive) and when the list length is a multiple of 3
import random
numbers = [random.randint(0, 31) for _ in range(1296)]
def pack(n):
result = []
for i in range(0, len(n), 3):
result.append(n[i] << 10 | n[i+1] << 5 | n[i+2])
return ''.join(map(chr, result))
def unpack(s):
result = []
for o in map(ord, s):
for shift in 10, 5, 0:
result.append(o >> shift & 0x1F)
return result
packed = pack(numbers)
print(len(packed))
result = unpack(packed)
assert result == numbers
Output:
432
Note:
If the range of numbers was 1-31 then this technique (with a minor modification) could be used for any list length because zero could be used as a padding indicator as follows:
import random
numbers = [random.randint(1, 31) for _ in range(1295)]
def pack(n):
result = []
a = None
for i, x in enumerate(n):
match i % 3:
case 0:
a = x << 10
case 1:
a |= x << 5
case _:
result.append(a|x)
a = None
if a is not None:
result.append(a)
return ''.join(map(chr, result))
def unpack(s):
result = []
for o in map(ord, s):
for shift in 10, 5, 0:
if (n := o >> shift & 0x1F) == 0:
break
result.append(n)
return result
packed = pack(numbers)
print(len(packed))
result = unpack(packed)
assert result == numbers
You can easily store 32 unique values in one character, which means your 1296 numbers can fit in a string of 1296 characters.
For example:
import random
numbers = [random.randint(0, 31) for i in range(1296)]
def numbers_to_string(numbers):
return "".join(chr(ord("0") + number) for number in numbers)
def numbers_from_string(string):
return [ord(char) - ord("0") for char in string]
numbers_str = numbers_to_string(numbers)
numbers_roundtrip = numbers_from_string(numbers_str)
print(numbers_roundtrip == numbers)
Output:
True
These are the numbers and the characters used to represent them:
0 0
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
10 :
11 ;
12 <
13 =
14 >
15 ?
16 #
17 A
18 B
19 C
20 D
21 E
22 F
23 G
24 H
25 I
26 J
27 K
28 L
29 M
30 N
31 O
I am trying to build a standard function to convert any decimal value to its octal, hexadecimal and binary equivalent but it doesn't work for binary for some reason. I tried putting extra precautions into the conditional statement to check for base 2 but it still did not work.
This is the function (I know that this doesn't work well with hexadecimal values. I am going to take care of that afterwards):
def convert(num, base):
remainder = num % base
conv = []
if(remainder == 0):
conv.append('0')
elif(remainder != 0 and base == 2):
conv.append('1')
else:
conv.append(str(remainder))
result = ''.join(conv)
output = result[::-1]
return int(output)
In the line elif(remainder != 0 and base == 2):, I am checking if the remainder isn't 0 and the base is 2 to add a 1 into the temporary conv list. I am then converting the list to a string, reversing it and returning it as an int.
For example. If the input is 17, the output needs to be this:
1 1 1 1
2 2 2 10
3 3 3 11
4 4 4 100
5 5 5 101
6 6 6 110
7 7 7 111
8 10 8 1000
9 11 9 1001
10 12 A 1010
11 13 B 1011
12 14 C 1100
13 15 D 1101
14 16 E 1110
15 17 F 1111
16 20 10 10000
17 21 11 10001
These are the functions that take care of the input and the printing:
def print_formatted(number):
# your code goes here
for i in range(number):
print(
str(i + 1) + " " +
str(convert(i + 1, 8)) + " " +
str(convert(i + 1, 16)) + " " +
str((convert(i + 1, 2)))
)
if __name__ == '__main__':
n = int(input())
print_formatted(n)
Update
Instead of going through the entire equation, I decided to go with the built-in functions and trim the first two characters (i.e 0b) so it fits the format well. I am trying to space them away from each other based on the width of the binary output but I couldn't figure out a way of doing that. This is what I have so far:
def convert(num, base):
# get the highest power
val = ''
hex_char_list = ['A', 'B', 'C', 'D', 'E', 'F']
if(base == 2):
bin_num = bin(num)
bin_list = list(bin_num)
bin_list_2 = bin_list[2:]
val = ''.join(bin_list_2)
if(base == 8):
oct_num = oct(num)
oct_list = list(oct_num)
oct_list_2 = oct_list[2:]
val = ''.join(oct_list_2)
if(base == 16):
hex_num = hex(num)
hex_list = list(hex_num)
hex_list_2 = hex_list[2:]
val = ''.join(hex_list_2)
if val in hex_char_list:
val = val.upper()
return val
def print_formatted(number):
# your code goes here
width = len(convert(number, 2).format(number))
for i in range(number):
print(
str(i + 1) + width +
str(convert(i + 1, 8)) + width +
str(convert(i + 1, 16)) + width +
str((convert(i + 1, 2)))
)
if __name__ == '__main__':
n = int(input())
print_formatted(n)
Your elif is superflous - if you do %2 the result can be only 0 or 1 - no need to do handle it differently.
Your code does not convert the whole number - you check the modulo of the number, not how often your base (and higher powers of your base) fits into it.
You need to get the highest possible power for your base that fits into your number. Then you need to get how often that one fits into your number, subtract it from the number and continue with the remainder of that operation. You shrink your power by one, and continue until your num is 0. Then you accumulate all numbers into a string.
Your code fixed:
def convert(num, base):
# get the highest power
power = 0
while num // (base**(power+1)) > 0:
power += 1
# divide, remember, subtract - until down to the lowest power
result = []
while num >= 0:
p = base**power
if p == 1:
result.append(num)
break
result.append(num // p)
num -= result[-1]*p
power -= 1
return ''.join(map(str,result))
to get an output of:
1 1 1 1
2 2 2 10
3 3 3 11
4 4 4 100
5 5 5 101
6 6 6 110
7 7 7 111
8 10 8 1000
9 11 9 1001
10 12 10 1010
11 13 11 1011
12 14 12 1100
13 15 13 1101
14 16 14 1110
15 17 15 1111
16 20 10 10000
Or you use built-ins:
def make(i):
for k in range(i+1):
print(f"{k:>10} {bin(k):>10} {hex(k):>10} {oct(k):>10}")
# or slice away the prefixes:
# print(f"{k:>10} {bin(k)[2:]:>10} {hex(k)[2:]:>10} {oct(k)[2:]:>10}")
make(17)
Results in:
0 0b0 0x0 0o0
1 0b1 0x1 0o1
2 0b10 0x2 0o2
3 0b11 0x3 0o3
4 0b100 0x4 0o4
5 0b101 0x5 0o5
6 0b110 0x6 0o6
7 0b111 0x7 0o7
8 0b1000 0x8 0o10
9 0b1001 0x9 0o11
10 0b1010 0xa 0o12
11 0b1011 0xb 0o13
12 0b1100 0xc 0o14
13 0b1101 0xd 0o15
14 0b1110 0xe 0o16
15 0b1111 0xf 0o17
16 0b10000 0x10 0o20
17 0b10001 0x11 0o21
The issue is you take only the mod of your number (num % base), that is to say the rightmost ("least significant") bit. What we want is not the least significant bit, but the entire decomposition.
NB: the problem here applies to all other bases too (decimal, hexadecimal...).
Indeed, if you run
n = 1000
print_formatted(n)
with your functions, you get that the decomposition of 1000 in different bases is:
1000 0 8 0
(all of them are wrong).
Here, I propose a recursive implementation:
def convert(integerToConvert, base = 2):
'''
When given a num and a base, will get the
conversion of that number in that base
'''
# The negative integer case is not taken into account
if (integerToConvert < 0):
print("ERROR: INTEGER < 0")
return;
# When the integer is 0, we know that we are done. There is no more bit
if (integerToConvert == 0):
print("WE ARE DONE")
return;
# get the current least significant coeff in the integerToEncode
currentLeastSignificant = integerToConvert % base;
print(currentLeastSignificant)
# remove the least significant coeff and start again
convert((integerToConvert - currentLeastSignificant) / base, base)
I ran a few quick tests:
convert(17, 2)
1
0.0
0.0
0.0
1.0
WE ARE DONE
convert(16, 2)
0
0.0
0.0
0.0
1.0
WE ARE DONE
convert(17, 16)
1
1.0
WE ARE DONE
NB1: I print numbers but you can store them in the data structure of your choice.
NB2: The most significant coefficient comes last in the printing (you can compare with your expected result)
NB3: all of these calculations are a bit expensive, so if speed matters to you, the best is actually to store all decompositions in arrays and access them (constant time).
In the following code snippet I am finding the sum of digits of all odd number between the interval [a,b]
def SumOfDigits(a, b):
s = 0
if a%2 == 0:
a+=1
if b%2 == 0:
b-=1
for k in range(a,b+1,2):
s+= sum(int(i) for i in list(str(k)))
return s
Is there an efficient way to accomplish the same?
Any patterns, which is leading to a clear cut formula.
I did search in https://oeis.org
Avoid all the overhead of conversion to and from strings and work directly with the numbers themselves:
def SumOfDigits(a, b):
result = 0
for i in range(a + (not a % 2), b + 1, 2):
while i:
result += i % 10
i //= 10
return result
Of course there is a pattern. Let's look at the problem of summing up the digitsums of all – odd and even – numbers between a and b inclusively.
For example: 17 to 33
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
The middle section gives you the sum of all digits from 0 to 9 (45) plus ten times 2. The left section is 7 + 8 + 9 plus three times 1 and the right the sum of 0 + 1 + 2 + 3 plus four times 3.
The middle section can comprise several blocks of ten, for example if you calculate the range between 17 and 63, you get 40 times 45 plus ten simes the the digitsums from 2 to 5.
This gives you a recursive algorithm:
def ssum(n):
return n * (n + 1) // 2
def dsum(a, b):
res = 0
if a == b:
while a:
res += a % 10
a //= 10
elif a < b:
aa = a // 10
bb = b // 10
ra = a % 10
rb = b % 10
if aa == bb:
res += ssum(rb) - ssum(ra - 1)
res += (rb - ra + 1) * dsum(aa, bb)
else:
if ra > 0:
res += 45 - ssum(ra - 1)
res += (10 - ra) * dsum(aa, aa)
aa += 1
if rb < 9:
res += ssum(rb)
res += (rb + 1) * dsum(bb, bb)
bb -= 1
if aa <= bb:
res += 45 * (bb - aa + 1)
res += 10 * dsum(aa, bb)
return res
Now let's extend this to include only odd numbers. Adkust a so that it is even and b so that it is odd. Your sum of digit sums now runs over pairs of even and odd numbers, where even + 1 == odd. That means that the digitsum of the odd number id one more than the even number, because all except the last digits are the same and the last odd digit is one more than the even digit.
Therefore:
dsum(a, b) == oddsum + evensum
and:
oddsum - evensum == (b - a + 1) // 2
The function to sum the digitsums of all odd numbers is then:
def oddsum(a, b):
if a % 2: a -= 1
if b % 2 == 0: b -= 1
d = (b - a + 1) // 2
return (dsum(a, b) + d) // 2
When I looked at your comment about OEIS, I've noticed that the algorithm can probably be simplified by writing a function to sum the digits from all numbers from zero to n and then calculate the difference dsum(b) - dsum(a). There are probably more opportunities for optimisation.
Is it possible to increase each step in range? Something like this:
for num in range(1, 40, i++) :
print(i)
...
1
2
3
4
...
Or step in range has only fixed size?
Yes, step in range has fixed size.
Something like this gives the output you want.
>>> j=0
>>> for i in xrange(1,40):
j+=i
print j
I think you want an increasing step size with each iteration?
The code below does this
>>> for i in (i+sum(range(i)) for i in (range (1,10))):
... print i
...
1
3
6
10
15
21
28
36
45
>>>
A while loop will result in cleaner code:
step = 1
i = 1
while i < 40:
print i, step
i += step
step +=1
result:
1 1
2 2
4 3
7 4
11 5
16 6
22 7
29 8
37 9
Using For loop
j = 0
for i in range(1,22):
j += i
if j <= 22:
print(j, end=" ")
Output:
1 3 6 10 15 21
I have this code:
def floyd(n):
count = 1
string = ""
for i in range(1,n+2):
for j in range(1,i):
string = string + " " + str(count)
count = count + 1
print(string)
string = ""
print floyd(6)
It prints:
1
2 3
4 5 6
7 8 9 10
11 12 13 14 15
16 17 18 19 20 21
But I want it to look like this:
1
2 3
4 5 6
7 8 9 10
11 12 13 14 15
16 17 18 19 20 21
Will you help me figure out how to do so?
Python strings actually have a built-in center() method that can do that for you.
print(string.center(total_width))
You can set up total_width in advance with:
total_width = -1
for i in xrange(0, n):
total_width += 1 + len(str((n + n * n) / 2 - i))
Or
total_width = sum(1 + len(str((n + n * n) / 2 - i)) for i in xrange(0, n)) - 1
That is, the sum of the lengths of the string representations of the numbers in the same row as the nth triangle number (n² + n) ÷ 2.
Here’s a demo!
Using n you can find the last row first, the last number is (n**2 + n)/2, so the first number on last line is ((n**2 + n)/2) - (n-1), now last row is can be created using str.join and a list comprehension:
x = ((n**2 + n)/2)
last_row = ' '.join(str(s) for s in xrange(x-(n-1), x+1))
Now we can use the width of this line in string formatting to center other lines properly.
Code:
from itertools import count
def floyd(n):
x = ((n**2 + n)/2)
last_row = ' '.join(str(s) for s in xrange(x-(n-1), x+1))
width = len(last_row)
c = count(1)
for x in xrange(1, n):
line = ' '.join(str(next(c)) for _ in xrange(x))
print "{:^{}}".format(line, width)
print last_row
Demo:
>>> floyd(6)
1
2 3
4 5 6
7 8 9 10
11 12 13 14 15
16 17 18 19 20 21
>>> floyd(8)
1
2 3
4 5 6
7 8 9 10
11 12 13 14 15
16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31 32 33 34 35 36
def FloydT(n):
num=0
row=""
for i in range(1,n+1):
for j in range(1,i+1):
num+=1
row+=str(num)+" "
print(str.center(row,3*n)) # this line will do what you want
row=""