Splitting arrays in unequal chunks using np.array_split: overcomplicating? - python

I am trying to convert an octal number to decimal.
The inputs are a set of strings as numbers such as "23", or "23 24", or "23 24 25". My code works for inputs like this, but cannot handle say "23 240", or "23 240 1" I.e. when the inputs are of different lengths, the array splits them incorrectly.
I think I've overcomplicated it by using arrays. Is there a way to assess each input individually (i.e. "23" then "240" then "1"), and then put these back into the desired output "19 160 1"?
Code:
import numpy as np
def decode(code):
decimals = []
code = code.split()
for n in code:
p = len(n)
for digit in n:
decimal = int(digit) * (8**(p - 1))
decimals.append(decimal)
p -= 1
split_input = np.array_split(decimals, len(code))
sum_decimals = []
for number in split_input:
sum_decimal = sum(map(int, number))
sum_decimals.append(str(sum_decimal))
separate_outputs = " ".join(sum_decimals)
return str(separate_outputs)

Does this work? Try running it in an instant interpreter such as Google Colab
CODE:
import numpy as np
def decode(code):
if isinstance(code, str):
decimals = []
code = code.split(' ')
for n in code:
p = len(n)
for digit in n:
decimal = int(digit) * (8**(p - 1))
decimals.append(decimal)
p -= 1
split_input = np.array_split(decimals, len(code))
sum_decimals = []
for number in split_input:
sum_decimal = sum(map(int, number))
sum_decimals.append(str(sum_decimal))
separate_outputs = " ".join(sum_decimals)
return str(separate_outputs)
INPUT:
str1 = input('Enter octals:') #23 240 1
decode(str1)
OUTPUT:
19 160 1
EXTRAS:
If you copy code make sure to adjust tabs because that could lead to
multiple errors.
Also, you could put an else statement to raise
error if function does not receive a string array. OR, you could add
multiple if...else statements to handle different data formats
like: str, int, list, tuple, etc.

Related

int 111 to binary 111(decimal 7)

Problem:Take a number example 37 is (binary 100101).
Count the binary 1s and create a binary like (111) and print the decimal of that binary(7)
num = bin(int(input()))
st = str(num)
count=0
for i in st:
if i == "1":
count +=1
del st
vt = ""
for i in range(count):
vt = vt + "1"
vt = int(vt)
print(vt)
I am a newbie and stuck here.
I wouldn't recommend your approach, but to show where you went wrong:
num = bin(int(input()))
st = str(num)
count = 0
for i in st:
if i == "1":
count += 1
del st
# start the string representation of the binary value correctly
vt = "0b"
for i in range(count):
vt = vt + "1"
# tell the `int()` function that it should consider the string as a binary number (base 2)
vt = int(vt, 2)
print(vt)
Note that the code below does the exact same thing as yours, but a bit more concisely so:
ones = bin(int(input())).count('1')
vt = int('0b' + '1' * ones, 2)
print(vt)
It uses the standard method count() on the string to get the number of ones in ones and it uses Python's ability to repeat a string a number of times using the multiplication operator *.
Try this once you got the required binary.
def binaryToDecimal(binary):
binary1 = binary
decimal, i, n = 0, 0, 0
while(binary != 0):
dec = binary % 10
decimal = decimal + dec * pow(2, i)
binary = binary//10
i += 1
print(decimal)
In one line:
print(int(format(int(input()), 'b').count('1') * '1', 2))
Let's break it down, inside out:
format(int(input()), 'b')
This built-in function takes an integer number from the input, and returns a formatted string according to the Format Specification Mini-Language. In this case, the argument 'b' gives us a binary format.
Then, we have
.count('1')
This str method returns the total number of occurrences of '1' in the string returned by the format function.
In Python, you can multiply a string times a number to get the same string repeatedly concatenated n times:
x = 'a' * 3
print(x) # prints 'aaa'
Thus, if we take the number returned by the count method and multiply it by the string '1' we get a string that only contains ones and only the same amount of ones as our original input number in binary. Now, we can express this number in binary by casting it in base 2, like this:
int(number_string, 2)
So, we have
int(format(int(input()), 'b').count('1') * '1', 2)
Finally, let's print the whole thing:
print(int(format(int(input()), 'b').count('1') * '1', 2))

Is it possible to convert a really large int to a string quickly in python

I am building an encryption program which produces a massive integer.It looks something like this:
a = plaintextOrd**bigNumber
when i do
a = str(a)
it takes over 28 minutes.
Is there any possible way to convert an integer like this quicker that using the built in str() function?
the reason i need it to be a string is because of this function here:
def divideStringIntoParts(parts,string):
parts = int(parts)
a = len(string)//parts
new = []
firstTime = True
secondTime = True
for i in range(parts):
if firstTime:
new.append(string[:a])
firstTime = False
elif secondTime:
new.append(string[a:a+a])
secondTime = False
else:
new.append(string[a*i:a*(i+1)])
string2 = ""
for i in new:
for i in i:
string2 += i
if len(string2) - len(string) != 0:
lettersNeeded = len(string) - len(string2)
for i in range(lettersNeeded):
new[-1] += string[len(string2) + i]
return new
You wrote in the comments that you want to get the length of the integer in decimal format. You don't need to convert this integer to a string, you can use "common logarithm" instead:
import math
math.ceil(math.log(a, 10))
Moreover, if you know that:
a = plaintextOrd**bigNumber
then math.log(a, 10) is equal to math.log(plaintextOrd, 10) * bigNumber, which shouldn't take more than a few milliseconds to calculate:
>>> plaintextOrd = 12345
>>> bigNumber = 67890
>>> a = plaintextOrd**bigNumber
>>> len(str(a))
277772
>>> import math
>>> math.ceil(math.log(a, 10))
277772
>>> math.ceil(math.log(plaintextOrd, 10) * bigNumber)
277772
It should work even if a wouldn't fit on your hard drive:
>>> math.ceil(math.log(123456789, 10) * 123456789012345678901234567890)
998952457326621672529828249600
As mentioned by #kaya3, Python standard floats aren't precise enough to describe the exact length of such a large number.
You could use mpmath (arbitrary-precision floating-point arithmetic) to get results with the desired precision:
>>> from mpmath import mp
>>> mp.dps = 1000
>>> mp.ceil(mp.log(123456789, 10) * mp.mpf('123456789012345678901234567890'))
mpf('998952457326621684655868656199.0')
Some quick notes on the "I need it for this function".
You don't need the first/second logic:
[:a] == [a*0:a*(0+1)]
[a:a+a] == [a*1:a*(1+1)]
So we have
new = []
for i in range(parts):
new.append(string[a*i:a*(i+1)])
or just new = [string[a*i:a*(i+1)] for i in range(parts)].
Note that you have silently discarded the last len(string) % parts characters.
In your second loop, you shadow i with for i in i, which happens to work but is awkward and dangerous. It can also be replaced with string2 = ''.join(new), which means you can just do string2 = string[:-(len(string) % parts)].
You then see if the strings are the same length, and then add the extra letters to the end of the last list. This is a little surprising, e.g. you would have
>>> divideStringIntoParts(3, '0123456789a')
['012', '345', '6789a']
When most algorithms would produce something that favors even distributions, and earlier elements, e.g.:
>>> divideStringIntoParts(3, '0123456789a')
['0124', '4567', '89a']
Regardless of this, we see that you don't really care about the value of the string at all here, just how many digits it has. Thus you could rewrite your function as follows.
def divide_number_into_parts(number, parts):
'''
>>> divide_number_into_parts(12345678901, 3)
[123, 456, 78901]
'''
total_digits = math.ceil(math.log(number + 1, 10))
part_digits = total_digits // parts
extra_digits = total_digits % parts
remaining = number
results = []
for i in range(parts):
to_take = part_digits
if i == 0:
to_take += extra_digits
digits, remaining = take_digits(remaining, to_take)
results.append(digits)
# Reverse results, since we go from the end to the beginning
return results[::-1]
def take_digits(number, digits):
'''
Removes the last <digits> digits from number.
Returns those digits along with the remainder, e.g.:
>>> take_digits(12345, 2)
(45, 123)
'''
mod = 10 ** digits
return number % mod, number // mod
This should be very fast, since it avoids strings altogether. You can change it to strings at the end if you'd like, which may or may not benefit from the other answers here, depending on your chunk sizes.
Faster than function str conversion of int to str is provided by GMPY2
Source of Example Below
import time
from gmpy2 import mpz
# Test number (Large)
x = 123456789**12345
# int to str using Python str()
start = time.time()
python_str = str(x)
end = time.time()
print('str conversion time {0:.4f} seconds'.format(end - start))
# int to str using GMPY2 module
start = time.time()
r = mpz(x)
gmpy2_str = r.digits()
end = time.time()
print('GMPY2 conversion time {0:.4f} seconds'.format(end - start))
print('Length of 123456789**12345 is: {:,}'.format(len(python_str)))
print('str result == GMPY2 result {}'.format(python_str==gmpy2_str))
Results (GMPY2 was 12 times faster in test)
str conversion time 0.3820 seconds
GMPY2 conversion time 0.0310 seconds
Length of 123456789**12345 is: 99,890
str result == GMPY2 result True

Print pi to a number of decimal places

One of the challenges on w3resources is to print pi to 'n' decimal places. Here is my code:
from math import pi
fraser = str(pi)
length_of_pi = []
number_of_places = raw_input("Enter the number of decimal places you want to
see: ")
for number_of_places in fraser:
length_of_pi.append(str(number_of_places))
print "".join(length_of_pi)
For whatever reason, it automatically prints pi without taking into account of any inputs. Any help would be great :)
The proposed solutions using np.pi, math.pi, etc only only work to double precision (~14 digits), to get higher precision you need to use multi-precision, for example the mpmath package
>>> from mpmath import mp
>>> mp.dps = 20 # set number of digits
>>> print(mp.pi)
3.1415926535897932385
Using np.pi gives the wrong result
>>> format(np.pi, '.20f')
3.14159265358979311600
Compare to the true value:
3.14159265358979323846264338327...
Why not just format using number_of_places:
''.format(pi)
>>> format(pi, '.4f')
'3.1416'
>>> format(pi, '.14f')
'3.14159265358979'
And more generally:
>>> number_of_places = 6
>>> '{:.{}f}'.format(pi, number_of_places)
'3.141593'
In your original approach, I guess you're trying to pick a number of digits using number_of_places as the control variable of the loop, which is quite hacky but does not work in your case because the initial number_of_digits entered by the user is never used. It is instead being replaced by the iteratee values from the pi string.
For example the mpmath package
from mpmath import mp
def a(n):
mp.dps=n+1
return(mp.pi)
Great answers! there are so many ways to achieve this. Check out this method I used below, it works any number of decimal places till infinity:
#import multp-precision module
from mpmath import mp
#define PI function
def pi_func():
while True:
#request input from user
try:
entry = input("Please enter an number of decimal places to which the value of PI should be calculated\nEnter 'quit' to cancel: ")
#condition for quit
if entry == 'quit':
break
#modify input for computation
mp.dps = int(entry) +1
#condition for input error
except:
print("Looks like you did not enter an integer!")
continue
#execute and print result
else:
print(mp.pi)
continue
Good luck Pal!
Your solution appears to be looping over the wrong thing:
for number_of_places in fraser:
For 9 places, this turns out be something like:
for "9" in "3.141592653589793":
Which loops three times, one for each "9" found in the string. We can fix your code:
from math import pi
fraser = str(pi)
length_of_pi = []
number_of_places = int(raw_input("Enter the number of decimal places you want: "))
for places in range(number_of_places + 1): # +1 for decimal point
length_of_pi.append(str(fraser[places]))
print "".join(length_of_pi)
But this still limits n to be less than the len(str(math.pi)), less than 15 in Python 2. Given a serious n, it breaks:
> python test.py
Enter the number of decimal places you want to see: 100
Traceback (most recent call last):
File "test.py", line 10, in <module>
length_of_pi.append(str(fraser[places]))
IndexError: string index out of range
>
To do better, we have to calculate PI ourselves -- using a series evaluation is one approach:
# Rewrite of Henrik Johansson's (Henrik.Johansson#Nexus.Comm.SE)
# pi.c example from his bignum package for Python 3
#
# Terms based on Gauss' refinement of Machin's formula:
#
# arctan(x) = x - (x^3)/3 + (x^5)/5 - (x^7)/7 + ...
from decimal import Decimal, getcontext
TERMS = [(12, 18), (8, 57), (-5, 239)] # ala Gauss
def arctan(talj, kvot):
"""Compute arctangent using a series approximation"""
summation = 0
talj *= product
qfactor = 1
while talj:
talj //= kvot
summation += (talj // qfactor)
qfactor += 2
return summation
number_of_places = int(input("Enter the number of decimal places you want: "))
getcontext().prec = number_of_places
product = 10 ** number_of_places
result = 0
for multiplier, denominator in TERMS:
denominator = Decimal(denominator)
result += arctan(- denominator * multiplier, - (denominator ** 2))
result *= 4 # pi == atan(1) * 4
string = str(result)
# 3.14159265358979E+15 => 3.14159265358979
print(string[0:string.index("E")])
Now we can take on a large value of n:
> python3 test2.py
Enter the number of decimal places you want: 100
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067
>
This is what I did, really elementary but works (max 15 decimal places):
pi = 22/7
while True:
n = int(input('Please enter how many decimals you want to print: '))
if n<=15:
print('The output with {} decimal places is: '.format(n))
x = str(pi)
print(x[0:n+2])
break
else:
print('Please enter a number between 0 and 15')
As this question already has useful answers, I would just like to share how i created a program for the same purpose, which is very similar to the one in the question.
from math import pi
i = int(input("Enter the number of decimal places: "))
h = 0
b = list()
for x in str(pi):
h += 1
b.append(x)
if h == i+2:
break
h = ''.join(b)
print(h)
Thanks for Reading.
Why not just use:
import numpy as np
def pidecimal(round):
print(np.round(np.pi, round))

How to print out a string of a '&', equal to the length of a list

I want to print out a list of the character '&' as many times as there are in a given number. So if the number is 10, I want the result to be '&&&&&&&&&&&'
What I have done is turned the int into a list so I can better visualize what I want to perform.
def print_list_&(size):
"""super serious docstring"""
result_1 = 1
result_2 = size + 1
result = list(range(result_1, result_2))
return result
I'm stuck on where I go from here. This is university work so I'm better off with a push in the right direction than a straight answer.
'&' * 10 will give you '&&&&&&&&&&'. Therefore it seems you just need '&' * size.
Python 2:
N = int(raw_input())
print '&' * N
Python 3:
N = int(input())
print ('&' * N)

Find length of a string that includes its own length?

I want to get the length of a string including a part of the string that represents its own length without padding or using structs or anything like that that forces fixed lengths.
So for example I want to be able to take this string as input:
"A string|"
And return this:
"A string|11"
On the basis of the OP tolerating such an approach (and to provide an implementation technique for the eventual python answer), here's a solution in Java.
final String s = "A String|";
int n = s.length(); // `length()` returns the length of the string.
String t; // the result
do {
t = s + n; // append the stringified n to the original string
if (n == t.length()){
return t; // string length no longer changing; we're good.
}
n = t.length(); // n must hold the total length
} while (true); // round again
The problem of, course, is that in appending n, the string length changes. But luckily, the length only ever increases or stays the same. So it will converge very quickly: due to the logarithmic nature of the length of n. In this particular case, the attempted values of n are 9, 10, and 11. And that's a pernicious case.
A simple solution is :
def addlength(string):
n1=len(string)
n2=len(str(n1))+n1
n2 += len(str(n2))-len(str(n1)) # a carry can arise
return string+str(n2)
Since a possible carry will increase the length by at most one unit.
Examples :
In [2]: addlength('a'*8)
Out[2]: 'aaaaaaaa9'
In [3]: addlength('a'*9)
Out[3]: 'aaaaaaaaa11'
In [4]: addlength('a'*99)
Out[4]: 'aaaaa...aaa102'
In [5]: addlength('a'*999)
Out[5]: 'aaaa...aaa1003'
Here is a simple python port of Bathsheba's answer :
def str_len(s):
n = len(s)
t = ''
while True:
t = s + str(n)
if n == len(t):
return t
n = len(t)
This is a much more clever and simple way than anything I was thinking of trying!
Suppose you had s = 'abcdefgh|, On the first pass through, t = 'abcdefgh|9
Since n != len(t) ( which is now 10 ) it goes through again : t = 'abcdefgh|' + str(n) and str(n)='10' so you have abcdefgh|10 which is still not quite right! Now n=len(t) which is finally n=11 you get it right then. Pretty clever solution!
It is a tricky one, but I think I've figured it out.
Done in a hurry in Python 2.7, please fully test - this should handle strings up to 998 characters:
import sys
orig = sys.argv[1]
origLen = len(orig)
if (origLen >= 98):
extra = str(origLen + 3)
elif (origLen >= 8):
extra = str(origLen + 2)
else:
extra = str(origLen + 1)
final = orig + extra
print final
Results of very brief testing
C:\Users\PH\Desktop>python test.py "tiny|"
tiny|6
C:\Users\PH\Desktop>python test.py "myString|"
myString|11
C:\Users\PH\Desktop>python test.py "myStringWith98Characters.........................................................................|"
myStringWith98Characters.........................................................................|101
Just find the length of the string. Then iterate through each value of the number of digits the length of the resulting string can possibly have. While iterating, check if the sum of the number of digits to be appended and the initial string length is equal to the length of the resulting string.
def get_length(s):
s = s + "|"
result = ""
len_s = len(s)
i = 1
while True:
candidate = len_s + i
if len(str(candidate)) == i:
result = s + str(len_s + i)
break
i += 1
This code gives the result.
I used a few var, but at the end it shows the output you want:
def len_s(s):
s = s + '|'
b = len(s)
z = s + str(b)
length = len(z)
new_s = s + str(length)
new_len = len(new_s)
return s + str(new_len)
s = "A string"
print len_s(s)
Here's a direct equation for this (so it's not necessary to construct the string). If s is the string, then the length of the string including the length of the appended length will be:
L1 = len(s) + 1 + int(log10(len(s) + 1 + int(log10(len(s)))))
The idea here is that a direct calculation is only problematic when the appended length will push the length past a power of ten; that is, at 9, 98, 99, 997, 998, 999, 9996, etc. To work this through, 1 + int(log10(len(s))) is the number of digits in the length of s. If we add that to len(s), then 9->10, 98->100, 99->101, etc, but still 8->9, 97->99, etc, so we can push past the power of ten exactly as needed. That is, adding this produces a number with the correct number of digits after the addition. Then do the log again to find the length of that number and that's the answer.
To test this:
from math import log10
def find_length(s):
L1 = len(s) + 1 + int(log10(len(s) + 1 + int(log10(len(s)))))
return L1
# test, just looking at lengths around 10**n
for i in range(9):
for j in range(30):
L = abs(10**i - j + 10) + 1
s = "a"*L
x0 = find_length(s)
new0 = s+`x0`
if len(new0)!=x0:
print "error", len(s), x0, log10(len(s)), log10(x0)

Categories