python fixed string size - python

Suppose I need a n elements long with each element seperated by a space. Further, I need the ith element to be a 1 and the rest to be a 0. What's the easiest pythonic way to do this?
Thus if n = 10, and i = 2, I would want
0 1 0 0 0 0 0 0 0 0
I want something like a new string[] that you can get in C++ but the Python version is eluding me.
Thanks!

Use a list.
n = 10
i = 2
mylist = ["0"] * n
mylist[i-1] = "1"
print " ".join(mylist)

The following Python generator expression should produce what you are looking for:
" ".join("1" if i == (x+1) else "0" for x in range(n))

The following example from the Python REPL should help you. The Python generator expression " ".join(bin((1<<n)+(1<<n>>i))[3:]) should be a solution.
>>> n=10
>>> i=2
>>> " ".join(bin((1<<n)+(1<<n>>i))[3:])
'0 1 0 0 0 0 0 0 0 0'

Just use "+" to join strings:
("0 "*i + "1 " + "0 "*(n-i-1))[:-1]
or you can also use bytearray:
a = bytearray(("0 "*n)[:-1])
a[i*2] = "1"
print str(a)

This looks like homework, so I'll describe my answer in English instead of Python.
Use a list comprehension to create a list of n strings, selecting each element from either '1' (if the index of the item is i) and '0' (otherwise). Join the elements of the list with a space between them.
There are several ways you can select from two items based on a boolean value. One of them would be to have the two items in a sequence, and index the sequence with the boolean value, thus picking the first element if False, and the second element if True. In this particular case, you can also convert the boolean value to '0' or '1' in several ways (e.g. convert to integer and then to string).
I don't understand the new string[] comment -- that's not C++ syntax.
Edit
Here's the Python:
' '.join([('0', '1')[x == i - 1] for x in range(n)])
or
' '.join([str(int(x == i - 1)) for x in range(n)])
I like the former more -- it's quite clear that it generates zeros and ones, and they can be changed to something else with ease. It's i - 1 instead of i to adjust for i being one-based and x being zero-based. Normally, I wouldn't do that. All things being equal, I prefer to work with zero-based indices throughout, except when input and output formats demand one-based values. In that case, I convert inputs as soon as possible and outputs as late as possible, and definitely avoid mixing the two in the same bit of code.
You can safely drop the square brackets, turning the list comprehension into a generator comprehension. For most intents and purposes, they work the same.

Related

Stacking inline For plus If else

I wrote a line that should sum up all numbers of a string except 0. On a zero it should add 5.
Whats wrong with
s="123450"
o=sum([int(x) for x in s if int(x) != 0 else 5])
it gives syntax error, but
s="123450"
o=sum([int(x) for x in s if int(x) != 0])
works fine.
if at the end of a list comprehension is used as a filter. It can only cause values to be dropped, not replace them with other things. To map values, you have to move the if/else earlier in the comprehension:
o=sum([int(x) if int(x) != 0 else 5 for x in s])
The correct syntax for the first case if -
s="123450"
o=sum([int(x) if int(x) != 0 else 5 for x in s ])
print(o)
OUTPUT :
20
There are many good answers already available on StackOverflow over if-else in list comprehension. Check these -
if else in a list comprehension
List comprehension with if statement
if/else in a list comprehension
More of an aside really (as the general issue of how you are using if inside list comprehensions is well covered in other answers), in this particular case you could do the following:
o = sum(int(x) or 5 for x in s)
This works because or will use the first value if it is "true" (which in the case of integers means non-zero) or the second value if the first is "false" (here, 0).
The other difference here is that I've used a generator expression instead of a list comprehension -- there is no need to build a list just in order to sum the values.

Randomly choosing a % of elements in a string and changing the value

I have a sting and need to randomly replace 5% of the elements, and flip them to 0 if they are 1, and flip them to 1 if they are 0.
I have a string that looks like this:
'10011110110001000111010011010100101100100110111000010001111100001010000011101100011110100110001110010101010000100111000101001100100110110010010100000010111110000011001001011011010111111010001011101011110100000101010110100001001011010000111110101011001101011000100100010010100011100001011011110001010101010101100001111111010101000010011010010110111100011111001011100101001000101011110000010111101111101100010010010011011101101110110000000000101010101010101011111011010111000101010010001010110011101011'
Effectively, 5% of the values in the string will change from a 0 to 1, or vice versa.
I have tried this but it does not seem to work, and isn't guaranteed to only replace 5% of the elements:
for i in range(500):
if random.random() < 0.05:
if test[i] == '1':
test[i] == '0'
else:
test[i] == '1'
You need to change two things
strings are immutable. So, test = list(test) before your loop, and test = ''.join(test) after it
Choose in advance which elements you want to change
First, choose n random indexes. One option is using random.choice without replacement
num_elements = int(0.05 * len(test))
indexes = random.choice(list(range(len(test)), num_elements, replace=False)
and then modify the values as before.
This will work on Python 2.7 and 3.6 (tested; probably newer as well).
import random
sting = '10011110110001000111010011010100101100100110111000010001111100001010000011101100011110100110001110010101010000100111000101001100100110110010010100000010111110000011001001011011010111111010001011101011110100000101010110100001001011010000111110101011001101011000100100010010100011100001011011110001010101010101100001111111010101000010011010010110111100011111001011100101001000101011110000010111101111101100010010010011011101101110110000000000101010101010101011111011010111000101010010001010110011101011'
sting = ''.join([chr(ord(y) ^ 1) if x in random.sample(range(len(sting)),len(sting)//20) else y for x,y in enumerate(list(sting))])
print (sting)
I have tried this and it works, and is guaranteed to only replace 5% of the elements.
It toggles exactly 5% -- the length of sting divided by 20, which is 5% -- characters from 0 to 1 and from 1 to 0, without duplicates. Toggling is done with XOR operator and random.sample picks indices to replace "unique elements", i.e. without duplicates.

Remove numbers from list which contains some particular numbers in python

Given List:
l = [1,32,523,336,13525]
I am having a number 23 as an output of some particular function.
Now,
I want to remove all the numbers from list which contains either 2 or 3 or both 2 and 3.
Output should be:[1]
I want to write some cool one liner code.
Please help!
My approach was :
1.) Convert list of int into list of string.
2.) then use for loop to check for either character 2 or character 3 like this:
A=[x for x in l if "2" not in x] (not sure for how to include 3 also in this line)
3.) Convert A list into integer list using :
B= [int(numeric_string) for numeric_string in A]
This process is quiet tedious as it involves conversion to string of the number 23 as well as all the numbers of list.I want to do in integer list straight away.
You could convert the numbers to sets of characters:
>>> values = [1, 32, 523, 336, 13525]
>>> number = 23
>>> [value for value in values
... if set(str(number)).isdisjoint(set(str(value)))]
[1]
You're looking for the filter function. Say you have a list of ints and you want the odd ones only:
def is_odd(val):
return val % 2 == 1
filter(is_odd, range(100))
or a list comprehension
[x for x in range(100) if x % 2 == 1]
The list comprehension in particular is perfectly Pythonic. All you need now is a function that returns a boolean for your particular needs.

I can't figure out this sequence - 11110000111000110010

NOTE: This is for a homework assignment, but the portion I have a question on is ok to ask help for.
I have to script out a sequence 11110000111000110010 (i am using python) without using switches or if statements and only a maximum of 5 for and whiles.
I already have my script laid out to iterate, I just can't figure out the algorithm as recursive or explicit let alone whether the element's are 1's 2's or 4's =/
As much as we have learned so far there is no equation or algorithm to use to figure OUT the algorithm for sequence. Just a set of instructions for defining one once we figure it out. Does anyone see a pattern here I am missing?
EDIT: What I am looking for is the algorithm to determine the sequence.
IE the sequence 1,3,6,10,15 would come out to be a[n]=(a[n-1]+n) where n is the index of the sequence. This would be a recursive sequence because it relies on a previous element's value or index. In this case a[n-1] refers to the previous index's value.
Another sequence would be 2, 4, 6, 8 would come out to be a[n] = (n*2) which is an explicit sequence because you only require the current index or value.
EDIT: Figured it out thanks to all the helpful people that replied.... I can't believe I didn't see it =/
There are many possible solutions to this problem. Here's a reusable solution that simply decrements from 4 to 1 and adds the expected number of 1's and 0's.
Loops used : 1
def sequence(n):
string = ""
for i in range(n):
string+='1'*(n-i)
string+='0'*(n-i)
return string
print sequence(4)
There's another single-line elegant and more pythonic way to do this:
print ''.join(['1'*x+'0'*x for x in range(4,0,-1)])
Loops used : 1, Lines of code : 1
;)
Note how there's a nested structure here. In pseudocode (so you do the python yourself):
for i in 4 .. 1:
for b in 1 .. 0:
for j in 1 .. i:
print b
You could try this:
print ''.join(['1'*i+'0'*i for i in range(4,0,-1)])
b_len = 4
ones = '1111'
zeros = '0000'
s = ''
for n in range(b_len, -1, -1):
s = s + ones[:n] + zeros[:n]
print s
prints:
11110000111000110010
I see. Four "1" - four "0", three "1" - three "0", two "1" - two "0", one "1" - one "0". 20 digits in total. What it means I have no clue.
#!/usr/bin/python
s=''
i=4
while i >0:
s=s+'1'*i+'0'*i
i -=1
print s
11110000111000110010
Is it exactly this sequence or do you want to be abble to change the length of the 1st sequence of 1?
you can use a reversed iteration loop like in this code:
def askedseq(max1):
seq = [] # declaring temporary sequence
for i in range(max1,0,-1): # decreasing iteration loop
seq += i*[1] + i*[0] # adding the correctly sized subseq
return seq
print askedseq(4) #prints the required sequence
print askedseq(5) #prints the equivalent sequence with 11111
prints:
11110000111000110010
111110000011110000111000110010
you can also look at numpy to do such things

How to determine the sum of a group of integers without using recursion

This is my first post on Stack Overflow, and I'm hoping that it'll be a good one.
This is a problem that I thought up myself, and now I'm a bit embarrassed to say, but it's beating the living daylights out of me. Please note that this is not a homework exercise, scout's honor.
Basically, the program takes (as input) a string made up of integers from 0 to 9.
strInput = '2415043'
Then you need to break up that string of numbers into smaller groups of numbers, until eventually, the sum of those groups give you a pre-defined total.
In the case of the above string, the target is 289.
iTarget = 289
For this example, there are two correct answers (but most likely only one will be displayed, since the program stops once the target has been reached):
Answer 1 = 241, 5, 043 (241 + 5 + 043 = 289)
Answer 2 = 241, 5, 0, 43 (241 + 5 + 0 + 43 = 289)
Note that the integers do not change position. They are still in the same order that they were in the original string.
Now, I know how to solve this problem using recursion. But the frustrating part is that I'm NOT ALLOWED to use recursion.
This needs to be solved using only 'while' and 'for' loops. And obviously lists and functions are okay as well.
Below is some of the code that I have so far:
My Code:
#Pre-defined input values, for the sake of simplicity
lstInput = ['2','4','1','5','0','4','3'] #This is the kind of list the user will input
sJoinedList = "".join(lstInput) #sJoinedList = '2415043'
lstWorkingList = [] #All further calculuations are performed on lstWorkingList
lstWorkingList.append(sJoinedList) #lstWorkingList = ['2415043']
iTarget = 289 #Target is pre-defined
-
def SumAll(_lst): #Adds up all the elements in a list
iAnswer = 0 #E.g. lstEg = [2,41,82]
for r in _lst: # SumAll(lstEg) = 125
iAnswer += int(r)
return(iAnswer)
-
def AddComma(_lst):
#Adds 1 more comma to a list and resets all commas to start of list
#E.g. lstEg = [5,1001,300] (Note only 3 groups / 2 commas)
# AddComma(lstEg)
# [5,1,0,001300] (Now 4 groups / 3 commas)
iNoOfCommas = len(_lst) - 1 #Current number of commas in list
sResetString = "".join(_lst) #Make a string with all the elements in the list
lstTemporaryList = []
sTemp = ""
i = 0
while i < iNoOfCommas +1:
sTemp += sResetString[i]+',' #Add a comma after every element
i += 1
sTemp += sResetString[i:]
lstTemporaryList = sTemp.split(',') #Split sTemp into a list, using ',' as a separator
#Returns list in format ['2', '415043'] or ['2', '4', '15043']
return(lstTemporaryList)
return(iAnswer)
So basically, the Pseudo-code will look something like this:
Pseudo-Code:
while SumAll(lstWorkingList) != iTarget: #While Sum != 289
if(len(lstWorkingList[0]) == iMaxLength): #If max possible length of first element is reached
AddComma(lstWorkingList) #then add a new comma / group and
Reset(lstWorkingList) #reset all the commas to the beginning of the list to start again
else:
ShiftGroups() #Keep shifting the comma's until all possible combinations
#for this number of comma's have been tried
#Otherwise, Add another comma and repeat the whole process
Phew! That was quite a mouthfull .
I have worked through the process that the program will follow on a piece of paper, so below is the expected output:
OUTPUT:
[2415043] #Element 0 has reached maximum size, so add another group
#AddComma()
#Reset()
[2, 415043] #ShiftGroups()
[24, 15043] #ShiftGroups()
[241, 5043] #ShiftGroups()
#...etc...etc...
[241504, 3] #Element 0 has reached maximum size, so add another group
#AddComma()
#Reset()
[2, 4, 15043] #ShiftGroups()
[2, 41, 5043] #ShiftGroups()
#etc...etc...
[2, 41504, 3] #Tricky part
Now here is the tricky part.
In the next step, the first element must become 24, and the other two must reset.
#Increase Element 0
#All other elements Reset()
[24, 1, 5043] #ShiftGroups()
[24, 15, 043] #ShiftGroups()
#...etc...etc
[24, 1504, 3]
#Increase Element 0
#All other elements Reset()
[241, 5, 043] #BINGO!!!!
Okay. That is the basic flow of the program logic. Now the only thing I need to figure out, is how to get it to work without recursion.
For those of you that have been reading up to this point, I sincerely thank you and hope that you still have the energy left to help me solve this problem.
If anything is unclear, please ask and I'll clarify (probably in excruciating detail X-D).
Thanks again!
Edit: 1 Sept 2011
Thank you everyone for responding and for your answers. They are all very good, and definitely more elegant than the route I was following.
However, my students have never worked with 'import' or any data-structures more advanced than lists. They do, however, know quite a few list functions.
I should also point out that the students are quite gifted mathematically, many of them have competed and placed in international math olympiads. So this assignment is not beyond the scope of
their intelligence, perhaps only beyond the scope of their python knowledge.
Last night I had a Eureka! moment. I have not implemented it yet, but will do so over the course of the weekend and then post my results here. It may be somewhat crude, but I think it will get the job done.
Sorry it took me this long to respond, my internet cap was reached and I had to wait until the 1st for it to reset. Which reminds me, happy Spring everyone (for those of you in the Southern Hempisphere).
Thanks again for your contributions. I will choose the top answer after the weekend.
Regards!
A program that finds all solutions can be expressed elegantly in functional style.
Partitions
First, write a function that partitions your string in every possible way. (The following implementation is based on http://code.activestate.com/recipes/576795/.) Example:
def partitions(iterable):
'Returns a list of all partitions of the parameter.'
from itertools import chain, combinations
s = iterable if hasattr(iterable, '__getslice__') else tuple(iterable)
n = len(s)
first, middle, last = [0], range(1, n), [n]
return [map(s.__getslice__, chain(first, div), chain(div, last))
for i in range(n) for div in combinations(middle, i)]
Predicate
Now, you'll need to filter the list to find those partitions that add to the desired value. So write a little function to test whether a partition satisfies this criterion:
def pred(target):
'Returns a function that returns True iff the numbers in the partition sum to iTarget.'
return lambda partition: target == sum(map(int, partition))
Main program
Finally, write your main program:
strInput = '2415043'
iTarget = 289
# Run through the list of partitions and find partitions that satisfy pred
print filter(pred(iTarget), partitions(strInput))
Note that the result is calculated in a single line of code.
Result: [['241', '5', '043'], ['241', '5', '0', '43']]
Recursion isn't the best tool for the job anyways. itertools.product is.
Here's how I search it:
Imagine the search space as all the binary strings of length l, where l is the length of your string minus one.
Take one of these binary strings
Write the numbers in the binary string in between the numbers of your search string.
2 4 1 5 0 4 3
1 0 1 0 1 0
Turn the 1's into commas and the 0's into nothing.
2,4 1,5 0,4 3
Add it all up.
2,4 1,5 0,4 3 = 136
Is it 289? Nope. Try again with a different binary string.
2 4 1 5 0 4 3
1 0 1 0 1 1
You get the idea.
Onto the code!
import itertools
strInput = '2415043'
intInput = map(int,strInput)
correctOutput = 289
# Somewhat inelegant, but what the heck
JOIN = 0
COMMA = 1
for combo in itertools.product((JOIN, COMMA), repeat = len(strInput) - 1):
solution = []
# The first element is ALWAYS a new one.
for command, character in zip((COMMA,) + combo, intInput):
if command == JOIN:
# Append the new digit to the end of the most recent entry
newValue = (solution[-1] * 10) + character
solution[-1] = newValue
elif command == COMMA:
# Create a new entry
solution.append(character)
else:
# Should never happen
raise Exception("Invalid command code: " + command)
if sum(solution) == correctOutput:
print solution
EDIT:
agf posted another version of the code. It concatenates the string instead of my somewhat hacky multiply by 10 and add approach. Also, it uses true and false instead of my JOIN and COMMA constants. I'd say the two approaches are equally good, but of course I am biased. :)
import itertools
strInput = '2415043'
correctOutput = 289
for combo in itertools.product((True, False), repeat = len(strInput) - 1):
solution = []
for command, character in zip((False,) + combo, strInput):
if command:
solution[-1] += character
else:
solution.append(character)
solution = [int(x) for x in solution]
if sum(solution) == correctOutput:
print solution
To expand on pst's hint, instead of just using the call stack as recursion does, you can create an explicit stack and use it to implement a recursive algorithm without actually calling anything recursively. The details are left as an exercise for the student ;)

Categories