4

I wrote a program to list all the prime numbers less than a number the user inputs. When I run the program in PyCharm, the output is very nice: each number is properly situated on the line and no numbers are spread across two lines. However, when I run the program from the command line, the formatting gets weird, with numbers at the end of a row sometimes getting cut off.

Here is my code:

import prime_functions as pf

number = int(input("Find primes up to what number? "))
# Save primes to a list.
primes = pf.list_primes(number)

for prime in primes[0:len(primes)-1]:
    print(prime, end=', ')
print(primes[len(primes)-1])

# Print length of primes.
print(f'Number of primes less than {number}: {len(primes)}')

# Pause before exiting.
input()

The list_primes function simply checks whether each odd number from three to the user's number is prime and returns a list of all the primes it finds.

What I would like to do ideally is print a small slice of the primes list on each line (say, five elements per line), but I can't think of how to do that without abandoning the generality of the program and using a bunch of for-loops. Are there any Python tricks out there that will help me?

ndmeiri
  • 4,979
  • 12
  • 37
  • 45
Jeff Moorhead
  • 181
  • 1
  • 15
  • 2
    Please include your current and desired output. Also do this in any future questions where such info is relevant. – ndmeiri Dec 27 '17 at 20:21
  • Sounds like Pycharm does word-wrapping, which a command-line doesn't. You may want to look at `textwrap.wrap`. – Hugh Bothwell Dec 27 '17 at 20:34

4 Answers4

1

Try something like this:

# Gather primes in some way.
primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31]

# Group the primes.
per_line = 5
grouped_primes = [primes[i:i+per_line] for i in range(0, len(primes), per_line)]

# Print each group.
for group in grouped_primes:
    print(', '.join(str(x) for x in group))

Output

2, 3, 5, 7, 11
13, 17, 19, 23, 29
31

Explanation

After you gather the list of primes, group the entire list into slices of (in this example) 5 elements each. Change the per_line variable to change the number of primes printed on each line.

This code snippet will not handle the case when per_line is sufficiently large that the printed primes cause the console line to wrap.

I also shortened the printing step to one line by using join() on each group of primes.

You were concerned about "abandoning the generality of the program and using a bunch of for-loops," but this code snippet avoids a loss of generality and only uses one for-loop.

ndmeiri
  • 4,979
  • 12
  • 37
  • 45
1

You could keep track of the index you are at and print in accordance to how many you want on a single line. Using your code for example to print five on a line like requested:

count = 1
items_per_line = 5
for prime in primes[0:len(primes)-1]:
    if count % items_per_line != 0:
        print(prime, end=', ')
    else:
        print(prime, end=',\n')
    count += 1
if count % items_per_line != 0:
    print(primes[len(primes)-1])
else:
    print("\n" + str(primes[len(primes)-1]))

The modulus operator(%) will determine if count is a multiple of 5 and if it is then the print will add a new line to the end of the prime number. The output of primes = [1, 3, 5, 7, 11, 13, 17] will be:

1, 2, 3, 5, 7,
11, 13, 17
B3W
  • 166
  • 11
0

Here's another way to do it, using fixed width formatting and only one iteration through your list:

primes = [3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 47]
N = 5  # the number to print each line

print(
    ''.join(
        map(
            lambda x: " %2d\n" % x[1] if ((x[0]+1)%(N)==0) else " %2d" % x[1],
            enumerate(primes)
        )
    )
)

The output will be:

  3  5  7 11 13
 17 19 23 29 31
 37 41 47

The %2d in the string formatting says print my numbers using 2 spaces. The logic here is that you build a list of strings for printing. Every N digits, you add a newline (\n) to your string. Finally join the strings together with an empty string ('').

Note: enumerate returns a tuple of (index, value), so x[0] refers to the index in the list and x[1] refers to the value at that index.

pault
  • 41,343
  • 15
  • 107
  • 149
  • The columns will fall out of alignment for primes greater than 99 (primes with three or more digits). – ndmeiri Dec 27 '17 at 21:20
  • Agreed, but the user can modify the code to the desired fixed width. Or one can choose to compute the appropriate width based on the input. – pault Dec 27 '17 at 21:23
0

Here are a bunch of methods that print the list, nothing really stands out. I remember that at some point I've read something very nice on tabular I/O formatting, but I can't remember now.

code.py:

import sys
#import prime_functions as pf  # Decomment this line
from pprint import pprint as pp


def print_list(seq, items_per_line=5, chars_per_item=4):
    l = len(seq)
    for idx, element in enumerate(seq, start=1):
        if (idx and idx % items_per_line == 0) or idx == l:
            end = "\n"
        else:
            end = ", "
        print("{}".format(element).rjust(chars_per_item), end=end)


number = int(input("Find primes up to what number? "))
# Save primes to a list.
primes = list(range(1234, 1275))
#primes = pf.list_primes(number)  # Decomment this line (, and comment the one above)

if not primes:
    print("Empty list returned. Exiting...")
    sys.exit()

print("\n1 - Original method:")
for prime in primes[:-1]:
    print(prime, end=', ')
print(primes[-1])

print("\n2 - Elements one by one (not much of a difference):")
print(*primes)

print("\n3 - pprint:")
pp(primes, compact=True)

print("\n4 - Custom method 0:")
print_list(primes)


# Print length of primes.
print(f'\nNumber of primes less than {number}: {len(primes)}')

# Pause before exiting.
input("\nPress ENTER to exit...")

Output (truncated lines to look exaclty as in my (140 chars wide) cmd console):

(py36x64_test) e:\Work\Dev\StackOverflow\q47998156>"e:\Work\Dev\VEnvs\py36x64_test\Scripts\python.exe" code.py
Find primes up to what number? 0

1 - Original method:
1234, 1235, 1236, 1237, 1238, 1239, 1240, 1241, 1242, 1243, 1244, 1245, 1246, 1247, 1248, 1249, 1250, 1251, 1252, 1253, 1254, 1255, 1256, 12
57, 1258, 1259, 1260, 1261, 1262, 1263, 1264, 1265, 1266, 1267, 1268, 1269, 1270, 1271, 1272, 1273, 1274

2 - Elements one by one (not much of a difference):
1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 
1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274

3 - pprint:
[1234, 1235, 1236, 1237, 1238, 1239, 1240, 1241, 1242, 1243, 1244, 1245, 1246,
1247, 1248, 1249, 1250, 1251, 1252, 1253, 1254, 1255, 1256, 1257, 1258, 1259,
1260, 1261, 1262, 1263, 1264, 1265, 1266, 1267, 1268, 1269, 1270, 1271, 1272,
1273, 1274]

4 - Custom method 0:
1234, 1235, 1236, 1237, 1238
1239, 1240, 1241, 1242, 1243
1244, 1245, 1246, 1247, 1248
1249, 1250, 1251, 1252, 1253
1254, 1255, 1256, 1257, 1258
1259, 1260, 1261, 1262, 1263
1264, 1265, 1266, 1267, 1268
1269, 1270, 1271, 1272, 1273
1274

Number of primes less than 0: 41

Press ENTER to exit...
CristiFati
  • 38,250
  • 9
  • 50
  • 87