Reverse characters of string in subset of 3 - python

Let say my string is as:
x = 'abcdefghi'
I want to reverse it in subsets of 3, so that my output is:
x = 'cbafedihg'
i.e. 0th index is swapped with 2nd index, 3rd index swapped with 5th, and so on.
Below is my code based on converting the string to list and swap the elements within the list:
string_list = list(x)
for i in range(len(string_list)/3):
string_list[i*3], string_list[i*3+2] = string_list[i*3+2], string_list[i*3]
''.join(string_list)
# Output: 'cbafedihg'
I want to know what will be the most efficient and most pythonic way to achieve it.
Note: len(x)%3 will always be 0.

The above code can be written using string slicing and list comprehension as:
# Here x[i*3:i*3+3][::-1] will reverse the substring of 3 chars
>>> ''.join([x[i*3:i*3+3][::-1] for i in range(len(x)/3)])
'cbafedihg'
Based on the comment by Delgan, it could be further simplified using step as 3 with range itself as:
>>> ''.join(x[i:i+3][::-1] for i in range(0, len(x), 3))
'cbafedihg'

Writing a function that is more readable and flexible?
def get_string(input_str, step=3):
output = ""
i = 0
for _ in list(input_str):
if i == len(input_str):
return output
elif i+step-1 >= len(input_str):
output += input[len(input_str)-1:i-1:-1]
return output
else:
output += input_str[i+step-1:i:-1] + input_str[i]
i += step
return output
And here comes the flexible part:
get_string("abcdefghi")
# Ouputs 'cbafedihg'
get_string("abcdefghi", 2)
# Outputs 'badcfehgi'
get_string("abcdefghi", 5)
# Outputs 'edcbaihgf'
Not to mention, if you want to add some more logic or change the logic, it is easier to change here.

Another alternative to achieve this is to type-cast your string to list, then simply swap the elements of list using list slicing with step as 3, and join back the list of strings as:
>>> string_list = list(x)
>>> string_list[::3], string_list[2::3] = string_list[2::3], string_list[::3]
>>> ''.join(string_list)
'cbafedihg'

Related

Split List based on range into multiple list :PYTHON

I have a small doubt , and i was not able to solve it , consider i have a list seperated with comma , and the data is dynamic may be 2 data or more than that
example : listVaue = ['Server1,Stop,Server2,START,.....,ServerN,StartN/StopN']
where N is a number
so if i have to split this into something like [[Server1,Stop],[Server2,Start2],....[ServerN,StartN/StopN]]
Is this possible . I wrote a code , but it is not working properly
listVaue = ['Server1,Stop,Server2,START']
c_index = listVaue.index("Stop")
l2 = listVaue[:c_index]
print(l2)
Can anyone help me solve this problem
This should work:
listValue = ["server1, stop, server2, start"]
listValue = listValue[0].split(",")
l2 = [[first_item, second_item] for first_item, second_item in zip(listValue[0::2], listValue[1::2])]
If you have a list defined as:
listVaue = ['Server1,Stop,Server2,START']
it actually only has one value, which is a string of value 'Server1,Stop,Server2,START'. If you can define a different list, I would suggest trying to do:
listVaue = ['Server1', 'Stop', 'Server2', 'START']
or even a list of tuples, if you would like values to be correspondent:
listVaue = [('Server1', 'Stop'), ('Server2', 'START')]
Now, if you don't have control over the input data (and therefore cannot change the original list), what you can do is to first split all values by comma and then aggregate them 2 by 2.
# Original list
listVaue = ['Server1,Stop,Server2,START']
# Split string into separate values
# Take the first element - from your code it looks
# like you only have a continuous string
new_list = listVaue[0].split(',')
# If you know that the list length will always be even, you can
# aggregate them 2 by 2 using the following code:
l2 = [(new_list[i], new_list.pop(i + 1)) for i in range(len(new_list) // 2)]
l2
>>> [('Server1', 'Stop'), ('Server2', 'START')]
What the code does is basically to get elements in position i and the next one as well (i + 1), removing the latter, whilst iterating through half the length of the list. Because you change its size as you iterate, always removing the second item, you'll end up only iterating through the original indexes 0, 2, 4, 6, 8..., whilst also retrieving their counterpart (1, 3, 5, 7, 9...).
Please note that changing the size of a list whilst you iterate is not generally a good practice, but because we are copying the original list, it shouldn't be a big problem for your case.
You can also change my code to whatever suits you, and you're probably better off with a normal for loop instead of a list comprehension:
listVaue = ['Server1,Stop,Server2,START']
new_list = listVaue[0].split(',')
l2 = []
for i in range(len(my_list) // 2):
# Change square brackets to round ones if you want a tuple (immutable) instead
l2.append([new_list[i], new_list.pop(i + 1)]
print(l2)
Try this:
listVaue = ['Server1,Command1,9182,Running,START,Server2,Command2,8888,Running,RESTART,ServerN,CommandN,N,Running,restart']
listVaue = listVaue[0].split(',')
a = ['START', 'RESTART', 'STOP', 'BOUNCE']
s = []
l2 = []
for i in listVaue:
s.append(i)
if i.upper() in a:
l2.append(s)
s = []

Can i include multiple statements when creating a one-line for loop?

I have an array I want to iterate through. The array consists of strings consisting of numbers and signs.
like this: €110.5M
I want to loop over it and remove all Euro sign and also the M and return that array with the strings as ints.
How would I do this knowing that the array is a column in a table?
You could just strip the characters,
>>> x = '€110.5M'
>>> x.strip('€M')
'110.5'
def sanitize_string(ss):
ss = ss.replace('$', '').replace('€', '').lower()
if 'm' in ss:
res = float(ss.replace('m', '')) * 1000000
elif 'k' in ss:
res = float(ss.replace('k', '')) * 1000
return int(res)
This can be applied to a list as follows:
>>> ls = [sanitize_string(x) for x in ["€3.5M", "€15.7M" , "€167M"]]
>>> ls
[3500000, 15700000, 167000000]
If you want to apply it to the column of a table instead:
dataFrame = dataFrame.price.apply(sanitize_string) # Assuming you're using DataFrames and the column is called 'price'
You can use a string comprehension:
numbers = [float(p.replace('€','').replace('M','')) for p in a]
which gives:
[110.5, 210.5, 310.5]
You can use a list comprehension to construct one list from another:
foo = ["€13.5M", "€15M" , "€167M"]
foo_cleaned = [value.translate(None, "€M")]
str.translate replaces all occurrences of characters in the latter string with the first argument None.
Try this
arr = ["€110.5M","€110.5M","€110.5M","€110.5M","€110.5M","€110.5M","€110.5M"]
f = [x.replace("€","").replace("M","") for x in arr]
You can call .replace() on a string as often as you like. An initial solution could be something like this:
my_array = ['€110.5M', '€111.5M', '€112.5M']
my_cleaned_array = []
for elem in my_array:
my_cleaned_array.append(elem.replace('€', '').replace('M', ''))
At this point, you still have strings in your array. If you want to return them as ints, you can write int(elem.replace('€', '').replace('M', '')) instead. But be aware that you will then lose everything after the floating point, i.e. you will end up with [110, 111, 112].
You can use Regex to do that.
import re
str = "€110.5M"
x = re.findall("\-?\d+\.\d+", str )
print(x)
I didn't quite understand the second part of the question.

Appending / concatenating one string to elements of a list of strings (Python 3.5)

Perhaps this has been answered, but I sincerely could not find it.
I wish to have a specific output in the form of:
("A_1", "A_2", ..., "A_100")
I tried:
a = "A_"
nums_1_100 = str(list(range(1,101)))
for i in range (1,101):
x = a
x += nums_1_100
And this returns:
'A_[1, 2, 3, 4, 5, ..., 100]'
Your code makes no sense as you overwrite x each iteration, which in result kills what your code produced in previous one. You want rather to use simple list comprehension instead:
result = [ 'A_%d' % i for i in range(1,101)]
which would then produce list with elements like A_1, A_2 ...
Try a list comprehension to make that list of strings like:
x = ['A_{}'.format(i) for i in range(1, 101)]
Here is the functional approach. This will work with a list of any type, so if you decided to switch from ints at the end to strings/characters, all that would need to change would be the contents of listToAppend.
listToAppend = list(range(1, 101))
output = list(map(lambda x: "A_" + str(x), listToAppend))

Python List Comprehension Setting Local Variable

I am having trouble with list comprehension in Python
Basically I have code that looks like this
output = []
for i, num in enumerate(test):
loss_ = do something
test_ = do something else
output.append(sum(loss_*test_)/float(sum(loss_)))
How can I write this using list comprehension such as:
[sum(loss_*test_)/float(sum(loss_))) for i, num in enumerate(test)]
however I don't know how to assign the values of loss_ and test_
You can use a nested list comprehension to define those values:
output = [sum(loss_*test_)/float(sum(loss_))
for loss_, test_ in ((do something, do something else)
for i, num in enumerate(test))]
Of course, whether that's any more readable is another question.
As Yaroslav mentioned in the comments, list comprehensions don't allow you to save a value into a variable directly.
However it allows you to use functions.
I've made a very basic example (because the sample you provided is incomplete to test), but it should show how you can still execute code in a list comprehension.
def loss():
print "loss"
return 1
def test():
print "test"
return 5
output = [loss()*test() for i in range(10) ]
print output
which is this case will result in a list [5, 5, 5, 5, 5, 5, 5, 5, 5, 5]
I hope this somehow shows how you could end up with the behaviour that you were looking for.
ip_list = string.split(" ") # split the string to a list using space seperator
for i in range(len(ip_list)): # len(ip_list) returns the number of items in the list - 4
# range(4) resolved to 0, 1, 2, 3
if (i % 2 == 0): ip_list[i] += "-" # if i is even number - concatenate hyphen to the current IP string
else: ip_list[i] += "," # otherwize concatenate comma
print("".join(ip_list)[:-1]) # "".join(ip_list) - join the list back to a string
# [:-1] trim the last character of the result (the extra comma)

Python - List.extend not returning expected value

I am trying to get a list all numbers divisible by three under 1000. I used this code:
y = []
for x in range(1000):
if not x % 3:
y.extend(str(x))
print y
However it simply returned a seemingly unordered list of integers under 10, repeated in no apparent order (If you would like to see this list just say, but it is very long and probably not useful). Does anyone know what I am doing wrong?
It is giving you the right numbers, it's just splitting them into individual characters.
Try list.append instead:
y.append(str(x))
Your meaning could be more explicit. It would make more sense to use x % 3 == 0 than not x % 3
This could also be summarised into a list comprehension:
y = [str(3 * i) for i in range(1000 / 3 + 1)]
Or, better yet (in my opinion), use map and range:
y = map(str, range(0, 1000, 3))
map applies the str function to every item in the list generated by range.
As pointed out in the comments, range creates a list of its own, the size of which depends on the length of the list. You can use xrange instead, to create an xrange object which can be used in the same way:
y = map(str, xrange(0, 1000, 3))
This avoids the creation of an intermediate list.
Your question is tagged python2.7 but note that in Python 3, the behaviour of range changes, so that it does what xrange does.
extend extends a list using another list. So when you try to extend a list using a string, it adds the digits of the number to the list.
>>> l = []
>>> l.extend(str(12))
>>> l
['1', '2']
The correct operator to use would be append, which appends a list to another list. But you should just do this instead:
y = [x for x in xrange(1000) if x%3 == 0] # use xrange in python2
Or just:
y = range(0, 1000, 3) # thanks to Sebastian for this
do:
y.append(str(x))
in place of
y.extend(str(x))
in case of extend, x considered to be list. For example, "123" considered as list with '1','2','3' as it's elements
Just another explanation and how to fix your snippet:
This is what list.extend says:
>>> help(list.extend)
Help on method_descriptor:
extend(...)
L.extend(iterable) -- extend list by appending elements from the iterable
>>>
In your case as string is iterable so it will iterable over your string and convert into a list of characters and extend to the original one.
So, we can fix your snippet using tuple or list instead of str:
Using single element tuple:
y = []
for x in range(1000):
if not x % 3:
y.extend((x,))
print y
Using single element list:
y = []
for x in range(1000):
if not x % 3:
y.extend([x])
print y

Categories