Swapping pairs of characters in a string - python

Okay, I'm really new to Python and have no idea how to do this:
I need to take a string, say 'ABAB__AB', convert it to a list, and then take the leading index of the pair I want to move and swap that pair with the __. I think the output should look something like this:
move_chars('ABAB__AB', 0)
'__ABABAB'
and another example:
move_chars('__ABABAB', 3)
'BAA__BAB'
Honestly have no idea how to do it.

Python strings are immutable, so you can't really modify a string. Instead, you make a new string.
If you want to be able to modify individual characters in a string, you can convert it to a list of characters, work on it, then join the list back into a string.
chars = list(str)
# work on the list of characters
# for example swap first two
chars[0], chars[1] = chars[1], chars[0]
return ''.join(chars)

I think this should go to the comment section, but I can't comment because of lack of reputation, so...
You'll probably want to stick with list index swapping, rather than using .pop() and .append(). .pop() can remove elements from arbitrary index, but only one at once, and .append() can only add to the end of the list. So they're quite limited, and it would complicate your code to use them in this kind of problems.
So, well, better stick with swapping with index.

The trick is to use list slicing to move parts of the string.
def move_chars(s, index):
to_index = s.find('__') # index of destination underscores
chars = list(s) # make mutable list
to_move = chars[index:index+2] # grab chars to move
chars[index:index+2] = '__' # replace with underscores
chars[to_index:to_index+2] = to_move # replace underscores with chars
return ''.join(chars) # stitch it all back together
print(move_chars('ABAB__AB', 0))
print(move_chars('__ABABAB', 3))

Related

Trying to sort two combined strings alphabetically without duplicates

Challenge: Take 2 strings s1 and s2 including only letters from a to z. Return a new sorted string, the longest possible, containing distinct letters - each taken only once - coming from s1 or s2.
# Examples
a = "xyaabbbccccdefww"
b = "xxxxyyyyabklmopq"
assert longest(a, b) == "abcdefklmopqwxy"
a = "abcdefghijklmnopqrstuvwxyz"
assert longest(a, a) == "abcdefghijklmnopqrstuvwxyz"
So I am just starting to learn, but so far I have this:
def longest(a1, a2):
for letter in max(a1, a2):
return ''.join(sorted(a1+a2))
which returns all the letters but I am trying to filter out the duplicates.
This is my first time on stack overflow so please forgive anything I did wrong. I am trying to figure all this out.
I also do not know how to indent in the code section if anyone could help with that.
You have two options here. The first is the answer you want and the second is an alternative method
To filter out duplicates, you can make a blank string, and then go through the returned string. For each character, if the character is already in the string, move onto the next otherwise add it
out = ""
for i in returned_string:
if i not in out:
out += i
return out
This would be empedded inside a function
The second option you have is to use Pythons sets. For what you want to do you can consider them as lists with no dulicate elements in them. You could simplify your function to
def longest(a: str, b: str):
return "".join(set(a).union(set(b)))
This makes a set from all the characters in a, and then another one with all the characters in b. It then "joins" them together (union) and you get another set. You can them join all the characters together in this final set to get your string. Hope this helps

How to print string tuple without commas

I'm new to Python, If i have this tuple
testGrid = [['p','c','n','d','t','h','g'],
['w','a','x','o','a','x','f'],
['o','t','w','g','d','r','k'],
['l','j','p','i','b','e','t'],
['f','v','l','t','o','w','n']]
How can I print it out so that it reads without any commas and without spaces? And new lines after each row?
pcndthg
waxoaxf
otwgdrk
ljpibet
fvltown
Use join() to concatenate all the strings in a list.
for row in testGrid:
print(''.join(row))
or change the default separator to an empty string.
for row in testGrid:
print(*row, sep='')
Barmar's answer is likely the most efficient possible way to do this in Python, but for the sake of learning programming logic, here is an answer that guides you through the process step by step:
First of all, in a nested list, usually 2 layers of loops are required (if no helper or built-in functions are used). Hence our first layer of for loop will have a 1D list as an element.
for row in testGrid:
print("something")
# row = ['p','c','n','d','t','h','g']
So within this loop, we attempt to loop through each alphabet in row:
for char in row:
print(char)
# char = 'p'
Since the built-in print() function in Python will move to the next line by default, we try to use a string variable to "stack" all characters before outputting it:
for row in testGrid:
# loop content applies to each row
# define string variable
vocab = ""
for char in row:
# string concatenation (piecing 2 strings together)
vocab = vocab + char
# vocab now contains the entire row, pieced into one string
print(vocab)
# remark: usually in other programming languages, moving cursor to the next line requires extra coding
# in Python it is not required but it is still recommended to keep this in mind
Hopefully this helps you understand programming concepts and flows better!

Convert bytes into list

I am new to this sort of stuff, so sorry if it's really simple and I am just being stupid.
So I have this variable with some bytes in it (not sure if that's the right name.)
data = b'red\x00XY\x001\x00168.93\x00859.07\x00'
I need to convert this to a list. The intended output would be something like.
["red","XY","1","169.93","859.07"]
How would I go about doing this?
Thank you for your help.
We can use the following line:
[x.decode("utf8") for x in data.split(b"\x00") if len(x)]
Going part by part:
x.decode("utf8"): x will be a bytes string, so we need to convert it into a string via `.decode("utf8").
for x in data.split(b"\x00"): We can use python's built in bytes.split method in order to split the byte string by the nullbytes to get an array of individual strings.
if len(x): This is equivalent to if len(x) > 0, since we want to discard the empty string at the end.
This code may help you to understand if you want exact same output using the pop() function.
data = 'red/x00XY/x001/x00168.93/x00859.07/x00' # I change "/" mark from "\" because i'm using Linux otherwise it will give error in Linux
new_list = [] # There is a variable that contain empty list
for item in data.split('/x00'): # Here I use split function by default it splits variable where "," appears but in this case
new_list.append(item) # you need list should be separated by "/" so that's why I gave split('/x00') and one by list appended
print(new_list)

Using pop on a list containing a string

I have a list:
listA = ['1,2,3,4,5']
where it is in string format. I want to perform a simple function that removes the last digit in the string, which in this case would be 5 and print it out.
I've tried something
listA = ['1,2,3,4,5']
for i in listA:
print(listA.pop())
What i tried is wrong as I'm not familiar with using pop on strings.
What you have is not a list of integers. It is a list with a single element, that element is a string of comma separated integers
You're not using i
You're iterating over the list and mutating it as you do so. Do not do this, because it does not give you the behaviour you expect.
I would recommend a while loop instead. First, fix your array.
listA = listA[0].split(',')
Now, iterate over it.
while listA:
print(listA.pop())
You use the truthiness of a nonempty list to keep iterating over it. This removes all the digits. However, if you just want the last digit and nothing more, call listA.pop() only once.
If you don't want to fix your array, you should extract the last digit like this:
listA = ['1,2,3,4,5']
print(int(listA[0][-1])) # [0] gets the string, [-1] gets the last character in the string
This is ungainly, so I recommend fixing your array instead.
The previous answer is giving you the last character. You can also extract the last value using split which will break up text based on a defined delimiter:
listA = ['1,2,3,4,5']
print( listA[0].split(',')[-1] )

Any way to split python string without generate new strings?

The input is a string containing a huge number of characters, and I hope to split this string into a list of strings with a special delimiter.
But I guess that simply using split would generate new strings rather than split the original input string itself, and in that case it consumes large memory(it's guaranteed that the original string would not be used any longer).
So is there a convenient way to do this destructive split?
Here is the case:
input_string = 'data1 data2 <...> dataN'
output_list = ['data1', 'data2', <...> 'dataN']
What I hope is that the data1 in output_list is and the data1(and all others) in input_string shares the same memory area.
BTW, for each input string, the size is 10MB-20MB; but as there are lots of such strings(about 100), so I guess memory consumption should be taken into consideration here?
In Python, strings are immutable. This means that any operation that changes the string will create a new string. If you are worried about memory (although this shouldn't be much of an issue unless you are dealing with gigantic strings), you can always overwrite the old string with the new, modified string, replacing it.
The situation you are describing is a little different though, because the input to split is a string and the output is a list of strings. They are different types. In this case, I would just create a new variable containing the output of split and then set the old string (that was the input to the split function) to None, since you guarantee it will not be used again.
Code:
split_str = input_string.split(delim)
input_string = None
The only alternative would be to access the substrings using slicing instead of split. You can use str.find to find the position of each delimiter. However this would be slow, and fiddly. If you can use split and get the original string to drop out of scope then it would be worth the effort.
You say that this string is input, so you might like to consider reading a smaller number of characters so you are dealing with more manageable chunks. Do you really need all the data in memory at the same time?
Perhaps the Pythonic way would be to use iterators? That way, the new substrings will be in memory only one at a time. Based on
Splitting a string into an iterator :
import re
string_long = "my_string " * 100000000 # takes some memory
# strings_split = string_long.split() # takes too much memory
strings_reiter = re.finditer("(\S*)\s*", string_long) # takes no memory
for match in strings_reiter:
print match.group()
This works fine without leading to memory problems.
If you're talking about strings that are SO huge that you can't stand to put them in memory, then maybe running through the string once (O(n), probably improvable using str.find but I'm not sure) then storing a generator that holds slice objects would be more memory-efficient?
long_string = "abc,def,ghi,jkl,mno,pqr" # ad nauseum
splitters = [','] # add whatever you want to split by
marks = [i for i,ch in enumerate(long_string) if ch in splitters]
slices = []
start = 0
for end in marks:
slices.append(slice(start,end))
start = end+1
else:
slices.append(slice(start,None))
split_string = (long_string[slice_] for slice_ in slices)

Categories

Resources