Pad each element of the list with the following 0s - python

I have a list of lists:
0 [[[20.5973832, 52.8685205], [20.5974081, 52.86...
1 [[[21.0072715, 52.2413049], [21.0072603, 52.24...
2 [[[18.8446673, 50.4508418], [18.8447041, 50.45...
3 [[[18.8649393, 50.4483321], [18.8649802, 50.44...
4 [[[16.7529018, 53.1424612], [16.7528965, 53..
I need to iterate over each element (each coordinate number) of the list, and make sure it has 7 digits after the period. If it doesn't, I need to pad it with a 0 at the end to make it to have 7 digits after the period.
Each number is a float, but I can convert it to string to use the len() function.
The code I have is:
for a in list_of_lists:
for b in a:
for c in b:
for d in c:
if(len(str(d))<10):
d = str(d).ljust(10-len(str(d)), '0')
The error I am getting is:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-46-70d9d844f41b> in <module>
3 for a in list_of_lists:
4 for b in a:
----> 5 for c in b:
6 for d in c:
7 if(len(str(d))<10):
TypeError: 'float' object is not iterable
What is the better way of achieving this?

recursive_tran is a recursive helper function to access every value in your list of list of whatever with possibility to replace or modify value.
(credit: Python: Replace values in nested dictionary)
Solution
3 Options I can see (you can run them by changing method parameter):
Custom Repr
It will not change anything at all, we just create new float class and override repr function with string formatter. This one is really nice as it formats without string apostrophes and value itself is not changed at all. I suggest this solution
String Substitution
Its pretty much the same like 1), but the difference is that we replace real float with formatted string, so you lose value, but you have what you wanted. Another downside is that the string has apostrophes
Rounding
The real deal, but not as nice as you want. It rounds the number up to 7 decimals, but the issue is, that if you have some number like 5.0, it will not give you all decimals you wants (5.0000000) as there is not really point to it.
See below for results
def recursive_tran(l: list, depth: int = 0, method: str = "round") -> list:
x = []
for e in l:
if isinstance(e, list):
e = recursive_tran(e, depth=depth + 1, method=method)
if isinstance(e, float) or isinstance(e, int):
if method == "round":
e = round(e, 7)
if method == "format":
e = format(e, ".7f")
if method == "custom_repr":
e = FakeRepresentationFloat(round(e, 7))
x.append(e)
return x
class FakeRepresentationFloat(float):
def __repr__(self):
return format(self, ".7f")
x = [[[1.0158, 5.7000155587, [[1, 2.000000000000000008]]]]]
print("Custom repr")
print(recursive_tran(x, method="custom_repr"))
print("String substitution")
print(recursive_tran(x, method="format"))
print("Rounding")
print(recursive_tran(x, method="round"))
>>> Custom repr
>>> [[[1.0158000, 5.7000156, [[1.0000000, 2.0000000]]]]]
>>> String substitution
>>> [[['1.0158000', '5.7000156', [['1.0000000', '2.0000000']]]]]
>>> Rounding
>>> [[[1.0158, 5.7000156, [[1, 2.0]]]]]

Related

Class pattern is matching the wrong cases

I'm writing an object serializer but am having issues where the class patterns are not matching the expected cases:
def dump_obj(x):
match(x):
case list():
emit('L')
dump_obj(len(x))
for elem in x:
dump_obj(elem)
case Iterable():
emit('I')
dump_obj((type(x), list(x)))
case tuple():
emit('T')
dump_obj(list(x))
case str():
emit('S')
dump_obj(len(x))
emit(x)
case int():
emit('D')
emit(str(x))
case _:
raise TypeError(f'Unknown obj {x!r}')
When I call dump_obj() with a tuple, it giving an infinite recursion on the I-case for iterables rather than matching the T-case for tuples.
When I call dump_obj() with a list subclass, it is matching the L-case for lists instead of the intended I-case for iterables.
First problem: Ordering
The cases are not independent of one another. They are tested from the top-down (like a long if/elif chain) and the first to match wins.
In the example, the specific match tests like like list, tuple, and str need to come before more general matches like Iterable. Otherwise with the current code, a tuple input like (10, 20, 30) will match the I-case instead of the intended T-case.
Second problem: Specificity
A class pattern performs an isinstance() check which would match both a type and subclasses of the type. To restrict the case to an exact match, use a type guard:
case list() if type(x) == list:
...
Putting it all together
With both solutions applied, here is the new code:
def dump_obj(x):
match(x):
case list() if type(x) == list: # <-- Added guard
emit('L')
dump_obj(len(x))
for elem in x:
dump_obj(elem)
case tuple() if type(x) == tuple: # <-- Added guard
emit('T')
dump_obj(list(x))
case str() if type(x) == str: # <-- Added guard
emit('S')
dump_obj(len(x))
emit(x)
case Iterable(): # <-- Move after list, tuple, str
emit('I')
dump_obj((type(x).__name__, list(x)))
case int():
emit('D')
emit(str(x))
case _:
raise TypeError(f'Unknown obj {x!r}')
Sample runs
Here we show that the two problematic cases work as expected.
>>> dump_obj((10, 20)) # Tuple of integers
T
L
D
2
D
10
D
20
>>> class List(list):
... pass
...
>>> dump_obj(List((30, 40))) # List subclass
I
T
L
D
2
S
D
4
List
L
D
2
D
30
D
40

Trying to split a string but I keep getting this error: "Type Error: must be str or None, not list"

Basically, I am trying to generate a random 4 digit number and then split that number and assign each digit to a separate variable. I'm new to python and I honestly have no idea what I am doing, I got the create random number code from the internet as well as the code to split the string so I can't really self diagnose the problem. Any help is appreciated!
from random import *
number = randint(1000,9999)
strnumber = str(number)
a,b,c,d = strnumber.split([strnumber[i:i+1] for i in range(0, len(strnumber), 1)])
print(a)
print(b)
print(c)
print(d)
The Error message is as follows:
Traceback (most recent call last):
File "D:\Documents HDD\Python\Mastermind Task.py", line 4, in
a,b,c,d = strnumber.split([strnumber[i:i+1] for i in range(0,
len(strnumber), 1)])
TypeError: must be str or None, not list
Edit: Okay, I promise I'm not a complete idiot, I simply copied the wrong thing into the post, I have fixed the rather embarrassing typos.
split() returns a list of strings, not a string itself. You will have to either parse that out and get the string from it, or since it's a single number, simply cast it with str()
There are two issues:
You refer to stringnumber instead of strnumber.
You are misusing str.split, which takes as an argument a delimiter. This function is not necessary.
So you can use:
a, b, c, d = (strnumber[i:i+1] for i in range(0, len(strnumber), 1))
However, note that strings are themselves iterable, so you can unpack directly:
a, b, c, d = strnumber
Or, if you need integers:
a, b, c, d = map(int, strnumber)
Alternatively, you can use mathematical operations and obviate the need for conversion between str and int:
from math import log10
d, c, b, a = (number // 10**i % 10 for i in range(int(log10(number))+1))
Notice we reverse the assignment order to reflect our calculation.
You went too far we can just assign the multiple variables to the string directly, but at the same time we can use map to make all the variables int
from random import randint
num = randint(1000,9999)
a, b, c, d = map(lambda x: int(x), str(num))
# 2 4 7 0
# <class 'int'> <class 'int'> <class 'int'> <class 'int'>
So right im a noob so i did it a noob's way But works none the less
from random import *
number = str(randint(1000,9999))
number = "{}".format(number)
print(number)
TheFour = ['','','','']
pos = 0
for i in number:
TheFour[pos] = i
pos += 1
print(i)
print(TheFour)
a = TheFour[0]
print(a)
b = TheFour[1]
print(b)
c = TheFour[2]
print(c)
d = TheFour[3]
print(d)
from random import *
number = randint(1000,9999)
strnumber = str(number)
a,b,c,d = [int(i) for i in str(strnumber)]
print a
print b
print c
print d

Repeat a number 3 times for output

I need to define a function which repeats a number 3 times. I can only get it to work as a list where the output is [1, 1, 1] if the input is 1. However I need the output to be 111
This is what I have
def repeat_number(num):
if not type(num) is int:
return None
list_1 = []
x = list_1.append(num)
y = list_1*3
for i in y:
return i,i,i
a = 12
print (repeat_number(a))
and again I want the output to be 121212
def repeat_number3(a):
return str(a)*3
You can use a simple str.join for this, and create a general function:
def repeat(something, times, separator):
return separator.join([str(something) for _ in range(times)])
And now use it to create your specific function:
def repeat_three_times(something):
return repeat(something, 3, '')
Output:
>>> repeat_three_times(1)
'111'
Few things to note:
I've used str to cast the expected integer to a string
I've used a list comprehension to create an iterable which is what str.join expects
I've used str.join to create a string which is a concatenation of the strings in the list (see 2).
Here is an example of using the more general function in a different way:
>>> repeat(1, 4, ',')
'1,1,1,1'
If the output is [1, 1, 1] and you were looking for 111, you can do the following:
print (*repeat_number(a), sep='')
However, I'd recommend doing the following with your function:
def repeat_number(num):
if type(num) != int: return
return int(str(num)*3)
And then all you have to do is:
print (repeat_number(a))
as you originally attempted. Plus, this function returns an actual number, which is probably good.
You can cast the number as a string and multiply.
def repeat(num):
return str(num)*3
a = 12
print(repeat(a))
def repeat_num(x):
return str(x)*3

Measure a length of tuples or string

I have following string and I want to convert it to array/list so I can measure its length.
a="abc,cde,ert,ert,eee"
b="a", "b", "c"
The expected length for a should be 1 and the expected length for b should be 3.
a is a string, b is a tuple. You can try something like this:
def length_of_str_or_tuple(obj):
if(isinstance(obj,basestring)):
return 1
return len(obj)
Although what you're doing is really weird and you should probably rethink your approach.
You can use something like this:
>>> a="abc,cde,ert,ert,eee"
>>> b="a", "b", "c"
>>> 1 if isinstance(a, str) else len(a)
1
>>> 1 if isinstance(b, str) else len(b)
3
>>>
In the above code, the conditional expression uses isinstance to test whether or not item is a string object. It returns 1 if so and len(item) if not.
Note that in Python 2.x, you should use isinstance(item, basestring) in order to handle both unicode and str objects.
There's a crude way to do this: check which is a string and which a tuple:
x ={}
for item in (a,b):
try:
item.find('')
x[item] = 1
except:
x[item] = len(item)
Since a tuple object doesn't have an attribute find, it will raise an exception.
To measure the length of the string:
len(a.split())
for the tuple:
len(list(b))
combine the previous answers to test for tuple or list and you would get what you want, or use:
if type(x) is tuple:
len(list(x))
else:
a = x.split("\"")
len(a)

subtraction operator python

I want to reduce the number of "the" words from a by 2. But this code doesn't seem to run. I cannot understand why the multiplication operator works but the subtraction operator doesn't.
b = "the"
a = b * 5
print a
a -= (b * 2)
print a
output
the
the the the the the
Traceback (most recent call last):
a -= (b * 2)
TypeError: unsupported operand type(s) for -=: 'str' and 'str'
How can I reduce the number of "the" 's in a by 2. If this cannot be done like this then is there a easier method perform this?
b = "the"
a = b * 5
print a
a = a[:-2*len(b)]
print a
# returns: thethethe
I am not substracting (you cannot really do it with strings), I am removing twice the length of b from the end of a, ignoring its real value.
To reduce the number of "the" by 2 in you word, try with the replace method :
b = "the"
a = b * 5
print a
>>> "thethethethethe"
a = a.replace(b, "", 2) # or a.replace(b*2, "", 1) if you want to remove "thethe" from the string
print a
>>> "thethethe"
If you wanted to remove the "the" by starting from the end, use rsplit()
b = "the"
a = "theAtheBthethe"
a = "".join(a.rsplit("the", 2)) # or "".join(a.rsplit("thethe", 1)) if you want to remove "theth" of the string
print a
>>> "theAtheB"
As described here, the * operator is supported by string (and unicode, list, tuple, bytearray, buffer, xrange types), b * 5 returns 5 copies of b concatenated.
Depends if you want to chop them off the start or the end, you can use array subsets:
>>> a[2*len("the"):]
'thethethe'
>>> a[:-(2*len("the"))]
'thethethe'
There is no support for subtraction operator in case of strings, but you can simply add one:
>>> class MyStr(str):
def __init__(self, val):
return str.__init__(self, val)
def __sub__(self, other):
if self.count(other) > 0:
return self.replace(other, '', 1)
else:
return self
and this will work in the following way:
>>> a = MyStr('thethethethethe')
>>> b = a - 'the'
>>> a
'thethethethethe'
>>> b
'thethethethe'
>>> b = a - 2 * 'the'
>>> b
'thethethe'
Regarding a - 2 * 'the' operation you should be aware that this is not " remove twice 'the' string from a ", but " remove result of (2 times 'the') from a " (first multiply "the" by 2 and then subtract from a).
Is this what you expected?
a = a.rpartition(b * 2)[0]
should do this, cutting from the right side. If you don't have any examples of 'thethe' in a, it will return the empty string ''. It won't work if you have multiple 'the's that are separated by other characters. For that, you could use a.rpartition(b)[0] twice. If you want to cut from the left instead, use a.partition(b * 2)[2].
Why doesn't subtracting work? Using addition and multiplication is a convenience feature for working with strings. The semantics of subtracting (or dividing) strs is not defined for Python, so you can't use it that way.
Plus operator work because "+" concatenate whilst minus don't operate on strings. You can try something using regular expression, like:
import re
s="the"*5
expr="the"
print s
# s -= 2
print "".join(re.findall(expr,s)[:-2])
# s -=3
print "".join(re.findall(expr,s)[:-3])

Categories