Python - Place a character in between a formatted string - python

Lets say I want to print out
Item 1 | Item 2
A Third item | #4
Which can be done without the | by doing
print('%s20 %20s' % (value1,value2))
How would I go about placing the | character so that it is evenly justified between the two formatted values?
I suppose I could manually could the length of the formatted string without the | character and then insert the | in the middle but I am hoping for a more elegant solution!
Thank you very much for your time.
Edit: Here is a solution that I suggested would be possible
def PrintDoubleColumn(value1, value2):
initial = '%s20 %20s' % (value1,value2)
lenOfInitial = len(initial)
print(initial[:lenOfInitial/2] +'|' + initial[lenOfInitial/2+1:])

There is a good source for string format operations: https://pyformat.info/#string_pad_align
x = [1, 2, 3, 4, 5]
y = ['a', 'b', 'c', 'd', 'e']
for i in range(0, 5):
print "{0:<20}|{1:>20}".format(x[i], y[i])
Result:
1 | a
2 | b
3 | c
4 | d
5 | e

Related

python pandas with parameter length changing

I want to do
df[(df['col']==50) | (df['col']==150) | etc ..]
"etc" is size changing from 1 to many
so I do a loop
result is like
str= "(df['col']==50) | (df['col']==150) | (df['col']==100)"
then I do this
df[str]
but this does not work
How can I make it work ?
A simple solution:
list_of_numbers = [50,150]
df[df["col"].isin(list_of_numbers)]
Where list_of_numbers are the numbers you want to include in the condition. I'm assuming here your condition is always or.
Use query to filter a dataframe from a string
df = pd.DataFrame({'col': range(25, 225, 25)})
l = [50, 100, 150]
q = ' | '.join([f"col == {i}" for i in l])
out = df.query(f)
>>> q
'col == 50 | col == 100 | col == 150'
>>> out
col
1 50
3 100
5 150

Add +1 to each item in a comma-separated string in pandas dataframe

I have a pandas dataframe structured as follows:
| ID | Start | Stop |
________________________________________
| 1 | 1,2,3,4 | 5,6,7,7 |
| 2 | 100,101 | 200,201 |
For each row in the dataframe, I'd like to add 1 to each value in the Start column. The dtype for the Start column is 'object'.
Desired output looks like this:
| ID | Start | Stop |
________________________________________
| 1 | 2,3,4,5 | 5,6,7,7 |
| 2 | 101,102 | 200,201 |
I've tried the following (and many versions of the following), but get an error stating ,TypeError: cannot concatenate 'str' and 'int' objects,:
df['test'] = [str(x + 1) for x in df['Start']]
I tried casting the column as an int, but got 'Invalid literal for long() with base 10: '101,102':
df['test'] = [int(x) + 1 for x in df['start'].astype(int)]
I tried converting the field to a list using str.split(), then casting each item as an integer:
Thanks in advance!
df['Start'] is the whole series, so you have to iterate that and then split:
new_series = []
for x in df['Start']:
value_list = []
for y in x.rstrip(',').split(','):
value_list.append(str(int(y) + 1))
new_series.append(','.join(value_list))
df['test'] = new_series
By telling you that you cannot concatenate string and int objects you know that x must be a string. You can solve this by casting x to an int before adding 1 to it. So str(x+1) becomes str(int(x)+1).
df['test'] = [str(int(x) + 1) for x in df['Start']]
df = pd.DataFrame({'Start' : [ [1 , 2, 3 , 4] , [100 , 101] ] , 'Stop' : [ [5 , 6 , 7 ,7] , [200,201] ] })
df.Start = df.Start.apply(lambda x : [y + 1 for y in x ])

How to create a table without using methods or for-loops?

I'm trying to create a 4x3 table without methods or for-loops.
I'd like to use what I learned in class, which is booleans, if-statements, and while-loops.
I want it so that if I input create_table('abcdefghijkl') it would start from the the left top most row and column and go down until the end of the column and then start again at the top of the next column and so on, like displayed below:
| a | e | i |
| b | f | j |
| c | g | k |
| d | h | l |
Below is what I have so far. It's not complete. How do I add to the function so that after 4 rows down, the string should continue to the next column starting from the top?
I'm wracking my brain over this.
All examples I can find online uses for loops and methods to create tables such as these, but I'd like to implement the while loop for this one.
Thanks in advance!
def create_table(table):
t = "" + "|" + ""
i = 0
while i < 12:
t = t + " " + "|" + table[i] + " "
i=i+1
print(t)
return table
Think about it in terms of rows instead of columns. You're writing out a row at a time, not a column at a time, so look at the indices of the individual cells in the original list:
| 0 | 4 | 8 |
| 1 | 5 | 9 |
| 2 | 6 | 10 |
| 3 | 7 | 11 |
Notice each row's cells' indices differ by 4. Find a simple expression for the nth row's cells and the task will become much easier, as you'll essentially be printing out a regular table.
You can translate most for loops to while loops with a simple recipe, so if you figure out how to do it with a for loop, then you are good to go. If you have
for x in s:
{statements}
Make it
i = 0
while i < len(s):
x = s[i]
{statements}
i += 1
It just won't work for some enumerable types that don't support length and indexing, such as generators.
Because you are printing to the terminal, you would want to think about printing each horizontal row, rather than each vertical column. Try something like:
table = 'abcdefghijkl'
i = 0
while i < 4:
print("| {} | {} | {} |".format(table[i], table[i+4], table[i+8]))
i += 1

Remove Python list element

I have two list,
l1 = [1,2,3,4,5,6]
l2 = [3,2]
what i want is to remove the element of list l1 which is in l2, for that i have done something like this,
for x in l1:
if x in l2:
l1.remove(x)
it gives output like
[1, 3, 4, 5, 6]
but the output should be like
[1, 4, 5, 6]
can any one shed light on this.
This is easily explained like this.
consider the first array you have:
| 1 | 2 | 3 | 4 | 5 | 6 |
Now you start iterating
| 1 | 2 | 3 | 4 | 5 | 6 |
^
Nothing happens, iterator increments
| 1 | 2 | 3 | 4 | 5 | 6 |
^
2 gets removed
| 1 | 3 | 4 | 5 | 6 |
^
iterator increments
| 1 | 3 | 4 | 5 | 6 |
^
And voila, 3 is still there.
The solution is to iterate ove a copy of the vector e.g.
for x in l1[:]: <- slice on entire array
if x in l2:
l1.remove(x)
or to iterate in reverse:
for x in reversed(l1):
if x in l2:
l1.remove(x)
Which acts like this:
| 1 | 2 | 3 | 4 | 5 | 6 |
^
| 1 | 2 | 3 | 4 | 5 | 6 |
^
| 1 | 2 | 4 | 5 | 6 |
^
| 1 | 2 | 4 | 5 | 6 |
^
| 1 | 4 | 5 | 6 |
^
| 1 | 4 | 5 | 6 |
^
Why not making it a bit simpler? No need to actually iterate over l1 if we only want to remove elements present in l2:
for item in l2:
while item in l1:
l1.remove(item)
This gives you exactly the output desired...
Also, as commenters point out, if there is a possibility that we can have duplicates:
l1 = filter(lambda x: x not in l2, l1)
.. or many other variations using list comprehensions.
You want the outer loop to read:
for x in l1[:]:
...
You can't change a list while iterating over it and expect reasonable results. The above trick makes a copy of l1 and iterates over the copy instead.
Note that if order doesn't matter in the output list, and your elements are unique and hashable, you could use a set:
set(l1).difference(l2)
which will give you a set as output, but you can construct a list from it easily:
l1 = list(set(l1).difference(l2))
As others have said, you can't edit a list while you loop over it. A good option here is to use a list comprehension to create a new list.
removals = set(l2)
l1 = [item for item in l1 if item not in removals]
We make a set as a membership check on a set is significantly faster than on a list.
If the order and loss of duplicates in l1 do not matter:
list(set(l1) - set(l2))
The last list() is only required if you need the result as a list. You could also just use the resulting set, it's also iterable.
If you need it ordered you can of course call l.sort() on the resulting list.
Edit: Removed my original answer because even though it did give correct results, it did so for non-intuitive reasons, and is was not very fast either... so I've just left the timings:
import timeit
setup = """l1 = list(range(20)) + list(range(20))
l2 = [2, 3]"""
stmts = {
"mgilson": """for x in l1[:]:
if x in l2:
l1.remove(x)""",
"petr": """for item in l2:
while item in l1:
l1.remove(item)""",
"Lattyware": """removals = set(l2)
l1 = [item for item in l1 if item not in removals]""",
"millimoose": """for x in l2:
try:
while True: l1.remove(x)
except ValueError: pass""",
"Latty_mgilson": """removals = set(l2)
l1[:] = (item for item in l1 if item not in removals)""",
"mgilson_set": """l1 = list(set(l1).difference(l2))"""
}
for idea in stmts:
print("{0}: {1}".format(idea, timeit.timeit(setup=setup, stmt=stmts[idea])))
Results (Python 3.3.0 64bit, Win7):
mgilson_set: 2.5841989922197333
mgilson: 3.7747968857414813
petr: 1.9669433777815701
Latty_mgilson: 7.262900152285258
millimoose: 3.1890831105541793
Lattyware: 4.573971325181478
You're modifying the list l1 while you're iterating over it, this will cause weird behaviour. (The 3 will get skipped during iteration.)
Either iterate over a copy, or change your algorithm to iterate over l2 instead:
for x in l2:
try:
while True: l1.remove(x)
except ValueError: pass
(This should perform better than testing if x in l1 explicitly.) Nope, this performs terribly as l1 grows in size.
FWIW I get significantly different results than #Tim Pietzcker did using what I believe is more realistic input data set and by using a little more rigorous (but otherwise the same) approach to timing different people's answers.
The names and code snippets are the same as Tim's except I added a variation of the one named Lattyware called Lattyware_rev which determines what elements to keep rather than reject -- it turned out to be a slower than the former. Note that the two fastest don't preserve the order of l1.
Here's the latest timing code:
import timeit
setup = """
import random
random.seed(42) # initialize to constant to get same test values
l1 = [random.randrange(100) for _ in xrange(100)]
l2 = [random.randrange(100) for _ in xrange(10)]
"""
stmts = {
"Minion91": """
for x in reversed(l1):
if x in l2:
l1.remove(x)
""",
"mgilson": """
for x in l1[:]: # correction
if x in l2:
l1.remove(x)
""",
"mgilson_set": """
l1 = list(set(l1).difference(l2))
""",
"Lattyware": """
removals = set(l2)
l1 = [item for item in l1 if item not in removals]
""",
"Lattyware_rev": """
keep = set(l1).difference(l2)
l1 = [item for item in l1 if item in keep]
""",
"Latty_mgilson": """
removals = set(l2)
l1[:] = (item for item in l1 if item not in removals)""",
"petr": """
for item in l2:
while item in l1:
l1.remove(item)
""",
"petr (handles dups)": """
l1 = filter(lambda x: x not in l2, l1)
""",
"millimoose": """
for x in l2:
try:
while True: l1.remove(x)
except ValueError: pass
""",
"K.-Michael Aye": """
l1 = list(set(l1) - set(l2))
""",
}
N = 10000
R = 3
timings = [(idea,
min(timeit.repeat(stmts[idea], setup=setup, repeat=R, number=N)),
) for idea in stmts]
longest = max(len(t[0]) for t in timings) # length of longest name
exec(setup) # get an l1 & l2 just for heading length measurements
print('fastest to slowest timings of ideas:\n' +\
' ({:,d} timeit calls, best of {:d} executions)\n'.format(N, R)+\
' len(l1): {:,d}, len(l2): {:,d})\n'.format(len(l1), len(l2)))
for i in sorted(timings, key=lambda x: x[1]): # sort by speed (fastest first)
print "{:>{width}}: {}".format(*i, width=longest)
Output:
fastest to slowest timings of ideas:
(10,000 timeit calls, best of 3 executions)
len(l1): 100, len(l2): 10)
mgilson_set: 0.143126456832
K.-Michael Aye: 0.213544010551
Lattyware: 0.23666971551
Lattyware_rev: 0.466918513924
Latty_mgilson: 0.547516608553
petr: 0.552547776807
mgilson: 0.614238139366
Minion91: 0.728920176815
millimoose: 0.883061820848
petr (handles dups): 0.984093136969
Of course, please let me know if there's something radically wrong that would explain the radically different results.
l1 = [1, 2, 3, 4, 5, 6]
l2 = [3, 2]
[l1.remove(x) for x in l2]
print l1
[1, 4, 5, 6]

Print histogram in python 3

I have a word length_of_word | repetitions dictionary and I want to make a histogram of that like the one in link below using only python built in functions no numpy or anything like it.
http://dev.collabshot.com/show/723400/
Please help me out at least with some pointers.
I guess you must have a dict that looks like this one, right ?
>>> d = {1:1, 2:10, 3:10, 4:6, 5:5, 6:4, 7:2, 8:1}
>>> d
{1: 1, 2: 10, 3: 10, 4: 6, 5: 5, 6: 4, 7: 2, 8: 1}
If so, I have a function that does the trick:
>>> def histo(dict_words):
# Get max values, plus delta to ease display
x_max = max(dict_words.keys()) + 2
y_max = max(dict_words.values()) + 2
# print line per line
print '^'
for j in range(y_max, 0, -1):
s = '|'
for i in range(1, x_max):
if i in dict_words.keys() and dict_words[i] >= j:
s += '***'
else:
s += ' '
print s
# print x axis
s = '+'
for i in range(1, x_max):
s += '---'
s += '>'
print s
# print indexes
s = ' '
for i in range(1, x_max):
s += ' %d ' % i
print s
>>> histo(d)
^
|
|
| ******
| ******
| ******
| ******
| *********
| ************
| ***************
| ***************
| ******************
|************************
+--------------------------->
1 2 3 4 5 6 7 8 9
>>>
Ok, there's a little more work to display values on the left and to format correctly numbers greater than 10 not to have shift in indexes, but I think it's a good start :-)

Categories

Resources