Removing whitespaces in string representation of the list in Python - python

In this Python code
def addToArrayForm(num,k):
num_string = ""
answer = []
for n in num:
num_string += str(n)
num_string = int(num_string) + k # This is an integer
for i in str(num_string):
answer.append(int(i))
print(answer)
addToArrayForm([1,2,0,0], 34)
I get this output => [1, 2, 3, 4]
How can I turn this output [1, 2, 3, 4] to this => [1,2,3,4] (what i wanna do is to remove these spaces between items)?

You can use replace method.
>>> answer = [1, 2, 3, 4]
>>> print(answer)
[1, 2, 3, 4]
>>> newanser = str(answer).replace(' ', '')
>>> print(newanser)
[1,2,3,4]
Good luck in leetcode ;)

You want to join all elements of answer with a comma, and then surround it in brackets. Let's do that!
def addToArrayForm(num,k):
num_string = ""
answer = []
for n in num:
num_string += str(n)
num_string = int(num_string) + k # This is an integer
for i in str(num_string):
answer.append(int(i))
# print(answer)
# Convert each element of answer to string, then join them all by comma
answer_s = ",".join(str(i) for i in answer) # 1,2,3,4
# Format answer_s into a string, surround it by brackets, print
print(f"[{answer_s}]")
Try it online

Your entire script can be reduced as below.
Working backwards through the list, start with k and increase with d * (powers of 10).
ex: k + 0*1 + 0*10 + 2*100 + 1*1000
def addToArrayForm(num,k):
for i,d in enumerate(num[::-1]):
k += d*((10**i) or 1)
#reformat as you requested
k = f"[{','.join(str(k))}]"
print(k)
addToArrayForm([1,2,0,0], 34) #[1,2,3,4]
One thing to note is: You initially have a list and the spaces you are trying to get rid of are just how a list is printed. ALL of the answers are converting your list to a str, in order to provide the result you requested. This ignores your list. You may want to consider that spaces being printed in your console isn't affecting anything, and jumping through hoops just to get rid of them is a waste of effort. You end up with something that looks like a list in the console, but isn't a list, at all.
All that being said: If you decide to keep the results that you already have, but want to get to those results in a much cleaner way, you can do this:
def addToArrayForm(num,k):
for i,d in enumerate(num[::-1]):
k += d*((10**i) or 1)
#reformat to list
num = list(map(int, str(k)))
print(num)
addToArrayForm([1,2,0,0], 34)

Related

specific characters printing with Python

given a string as shown below,
"[xyx],[abc].[cfd],[abc].[dgr],[abc]"
how to print it like shown below ?
1.[xyz]
2.[cfd]
3.[dgr]
The original string will always maintain the above-mentioned format.
I did not realize you had periods and commas... that adds a bit of trickery. You have to split on the periods too
I would use something like this...
list_to_parse = "[xyx],[abc].[cfd],[abc].[dgr],[abc]"
count = 0
for i in list_to_parse.split('.'):
for j in i.split(','):
string = str(count + 1) + "." + j
if string:
count += 1
print(string)
string = None
Another option is split on the left bracket, and then just re-add it with enumerate - then strip commas and periods - this method is also probably a tiny bit faster, as it's not a loop inside a loop
list_to_parse = "[xyx],[abc].[cfd],[abc].[dgr],[abc]"
for index, i in enumerate(list.split('[')):
if i:
print(str(index) + ".[" + i.rstrip(',.'))
also strip is really "what characters to remove" not a specific pattern. so you can add any characters you want removed from the right, and it will work through the list until it hits a character it can't remove. there is also lstrip() and strip()
string manipulation can always get tricky, so pay attention. as this will output a blank first object, so index zero isn't printed etc... always practice and learn your needs :D
You can use split() function:
a = "[xyx],[abc].[cfd],[abc].[dgr],[abc]"
desired_strings = [i.split(',')[0] for i in a.split('.')]
for i,string in enumerate(desired_strings):
print(f"{i+1}.{string}")
This is just a fun way to solve it:
lst = "[xyx],[abc].[cfd],[abc].[dgr],[abc]"
count = 1
var = 1
for char in range(0, len(lst), 6):
if var % 2:
print(f"{count}.{lst[char:char + 5]}")
count += 1
var += 1
output:
1.[xyx]
2.[cfd]
3.[dgr]
explanation : "[" appears in these indexes: 0, 6, 12, etc. var is for skipping the next pair. count is the counting variable.
Here we can squeeze the above code using list comprehension and slicing instead of those flag variables. It's now more Pythonic:
lst = "[xyx],[abc].[cfd],[abc].[dgr],[abc]"
lst = [lst[i:i+5] for i in range(0, len(lst), 6)][::2]
res = (f"{i}.{item}" for i, item in enumerate(lst, 1))
print("\n".join(res))
You can use RegEx:
import regex as re
pattern=r"(\[[a-zA-Z]*\])\,\[[a-zA-Z]*\]\.?"
results=re.findall(pattern, '[xyx],[abc].[cfd],[abc].[dgr],[abc]')
print(results)
Using re.findall:
import re
s = "[xyx],[abc].[cfd],[abc].[dgr],[abc]"
print('\n'.join(f'{i+1}.{x}' for i,x in
enumerate(re.findall(r'(\[[^]]+\])(?=,)', s))))
Output:
1.[xyx]
2.[cfd]
3.[dgr]

Function that recieves an integer and returns a tuple with all of its' digits in order in Python

def function(n):
res = 0
if not isinstance(n, int):
raise ValueError('argument is not an integer')
else:
while n > 0: #inverting the integer's digits
dig = n % 10
res = 10*res + dig
n = n//10
dig2 = res % 10
res2 = (dig2,)
res = res // 10
while res > 0:
dig2 = res % 10
res2 = (res2,) + (dig2,)
res = res // 10
return res2
Input: 123
Output: (1, 2, 3)
With the current program that I have my output is (((1,), 2), 3).Im having trouble with creating a tuple and adding it to another tuple and also with the logic part of analyzing each digit. I'm new to python, if you could try to explain it to me wihtout the use of lists I'd also be very grateful.
I can't comment on efficiency/performance, but take a look at the following code:
num = 123456789
lis = [int(char) for char in str(num)]
tup = tuple(lis)
print(tup)
Output:
(1, 2, 3, 4, 5, 6, 7, 8, 9)
Here we are using list comprehensions (which are loved by Python programmers). First, num is converted to string, then each char of this string is converted to an int, building a list of integers. The list can then be converted to a tuple.
I know you said "if you could try to explain it to me wihtout the use of lists...", but understand that lists (and list comprehensions) are an important part/tool of Python, you should not avoid them.
Again, the list comprehension above can be "read" as such:
Convert to int each char in the string (where this string is the number converted to a string).

How to change list elements positions in a for loop in Python

I'm fairly new to programming and I'm really stuck in a problem.
Say I have the following list:
a = [2, "**", 2, "#"]
The list might contain more elements.
What I need to do is change positions between "**" and "#", so I would have
a = [2, "#", 2, "**"]
I've been trying to do it with a for loop, using element indexes to perform the change, but the list index is getting out of range.
How could I do it?
Here's my code:
for j in range (len(expression)):
if expression[j] == "**":
if expression[j+2] == "#":
expression[j], expression[j+2] = expression[j+2], expression[j]
print(expression)
My comment in an answer (altho pretty simple tbf)
>>> expression = [2, "**", 2, "#", "**"]
>>> for j in range (len(expression)):
... if expression[j] == "**":
... if (
... len(expression) > j +2
... and expression[j+2] == "#"
... ):
... expression[j], expression[j+2] = expression[j+2], expression[j]
...
>>> print(expression)
[2, '#', 2, '**', '**']
Explanation: if the current value is ** you are attempting to access j+2. However, your list might not have that index (for example what if ** is the last element?). To cater for this case I extend your if statement to first check for length and then check for j+2 values. If/when the first check/condition fails, the second condition is skipped (not checked) and thus the IndexError does not happen.
(updated the input list to show that even ** at the end of the list wont raise an error)
Try the below
# assuming "**" and "#" apper once in the list
a = [2, "**", 2, "#"]
idx_1 = a.index("**")
idx_2 = a.index("#")
# I need to change if and only if ** and # are separated by another element
if abs(idx_1 - idx_2) > 1:
del a[idx_1]
a.insert(idx_1,"#")
del a[idx_2]
a.insert(idx_2,"**")
print(a)
I thought about just getting the positions out of the list and then swapping them.
for idx , j in enumerate(a):
if (j == "**"):
pos1 = idx
elif (j=="#"):
pos2 = idx
a[pos1],a[pos2] = a[pos2],a[pos1]

Convert a string of integers represented in different formats into a list of integers Python

Is there an easy way, apart from looping, to convert this kind of representation to a list of integers?
s = ['0','1','2:5','0x4']
to
list_i=[0,1,2,3,4,5,0,0,0,0]
You can use a list comprehension with the ternary operator like this:
list_i = [i for t in s for i in ((lambda r: range(int(r[0]), int(r[1]) + 1))(t.split(':')) if ':' in t else (lambda r: [int(r[0])] * int(r[1]))(t.split('x')) if 'x' in t else (int(t),))]
or you can use a for loop instead:
list_i = []
for token in s:
if ':' in token:
start, end = token.split(':')
list_i.extend(list(range(int(start), int(end) + 1)))
elif 'x' in token:
number, repeat = token.split('x')
list_i.extend([int(number)] * int(repeat))
else:
list_i.append(int(token))
No, there isn't. You need to handle the special strings seperately. You need to loop through the list, check if the given element is a simple integer, if so, convert it as it is. If the element being considered is special (0x4 or 2:5 in your case), you need code to handle it. Try this:
oldList = ['0','1','2:5','0x4']
def isInt(val):
try:
int(val)
return True
except ValueError:
return False
def convertRange(val):
l = val.split(':')
return [x for x in range(int(l[0]), int(l[1])+1)]
def convertRepetition(val):
l = val.split('x')
return [int(l[0]) for i in range(0, int(l[1]))]
newList = []
for elem in oldList:
if ':' in elem:
newList.extend(convertRange(elem))
elif 'x' in elem:
newList.extend(convertRepetition(elem))
elif isInt(elem):
newList.append(int(elem))
print(newList)
the convertRange() and convertRepitition() functions take care of the two special cases your question mentions.
If you have the freedom to redefine how the s-list is set, you can use python syntax like this
s = ['[0]','[1]','range(2,6)','[0]*4']
list_i = []
[exec('list_i+='+i) for i in s]
print(list_i)
# which outputs
[0, 1, 2, 3, 4, 5, 0, 0, 0, 0]

Longest common prefix using buffer?

If I have an input string and an array:
s = "to_be_or_not_to_be"
pos = [15, 2, 8]
I am trying to find the longest common prefix between the consecutive elements of the array pos referencing the original s. I am trying to get the following output:
longest = [3,1]
The way I obtained this is by computing the longest common prefix of the following pairs:
s[15:] which is _be and s[2:] which is _be_or_not_to_be giving 3 ( _be )
s[2:] which is _be_or_not_to_be and s[8:] which is _not_to_be giving 1 ( _ )
However, if s is huge, I don't want to create multiple copies when I do something like s[x:]. After hours of searching, I found the function buffer that maintains only one copy of the input string but I wasn't sure what is the most efficient way to utilize it here in this context. Any suggestions on how to achieve this?
Here is a method without buffer which doesn't copy, as it only looks at one character at a time:
from itertools import islice, izip
s = "to_be_or_not_to_be"
pos = [15, 2, 8]
length = len(s)
for start1, start2 in izip(pos, islice(pos, 1, None)):
pref = 0
for pos1, pos2 in izip(xrange(start1, length), xrange(start2, length)):
if s[pos1] == s[pos2]:
pref += 1
else:
break
print pref
# prints 3 1
I use islice, izip, and xrange in case you're talking about potentially very long strings.
I also couldn't resist this "One Liner" which doesn't even require any indexing:
[next((i for i, (a, b) in
enumerate(izip(islice(s, start1, None), islice(s, start2, None)))
if a != b),
length - max((start1, start2)))
for start1, start2 in izip(pos, islice(pos, 1, None))]
One final method, using os.path.commonprefix:
[len(commonprefix((buffer(s, n), buffer(s, m)))) for n, m in zip(pos, pos[1:])]
>>> import os
>>> os.path.commonprefix([s[i:] for i in pos])
'_'
Let Python to manage memory for you. Don't optimize prematurely.
To get the exact output you could do (as #agf suggested):
print [len(commonprefix([buffer(s, i) for i in adj_indexes]))
for adj_indexes in zip(pos, pos[1:])]
# -> [3, 1]
I think your worrying about copies is unfounded. See below:
>>> s = "how long is a piece of string...?"
>>> t = s[12:]
>>> print t
a piece of string...?
>>> id(t[0])
23295440
>>> id(s[12])
23295440
>>> id(t[2:20]) == id(s[14:32])
True
Unless you're copying the slices and leaving references to the copies hanging around, I wouldn't think it could cause any problem.
edit: There are technical details with string interning and stuff that I'm not really clear on myself. But I'm sure that a string slice is not always a copy:
>>> x = 'google.com'
>>> y = x[:]
>>> x is y
True
I guess the answer I'm trying to give is to just let python manage its memory itself, to begin with, you can look at memory buffers and views later if needed. And if this is already a real problem occurring for you, update your question with details of what the actual problem is.
One way of doing using buffer this is give below. However, there could be much faster ways.
s = "to_be_or_not_to_be"
pos = [15, 2, 8]
lcp = []
length = len(pos) - 1
for index in range(0, length):
pre = buffer(s, pos[index])
cur = buffer(s, pos[index+1], pos[index+1]+len(pre))
count = 0
shorter, longer = min(pre, cur), max(pre, cur)
for i, c in enumerate(shorter):
if c != longer[i]:
break
else:
count += 1
lcp.append(count)
print
print lcp

Categories

Resources