2

I don't know if the title is the best for this question. (suggestions accepted)

I have a piece of code that gets 3 lists of integers from the user in three different lines and I was wondering if this code:

A, B, C = [int(a) for a in input().split()], [int(a) for a in input().split()], [int(a) for a in input().split()]

can be simplified in a pythonic way to something like:

A, B, C = [int(a) for a in input().split()]*3

I know that this incorrect code but, is there a way to do this?

the best solution I've thought about for now is:

A, B, C = [[int(a) for a in input().split()] for _ in range(3)]

I've been suggested that this might be a duplicate of this question and it's not, I'm not asking how to set multiple variables to the same value, the value is different but the function call is the same to get the values. This results in code with three statements that are identical on the right side of the = sign and just have different variable names, but the values are different.

Illic
  • 54
  • 6
  • Possible duplicate of [Python initialize multiple variables to the same initial value](https://stackoverflow.com/questions/33331732/python-initialize-multiple-variables-to-the-same-initial-value) – CDJB Nov 25 '19 at 16:27
  • 1
    "I know that this incorrect code" How so? That last line (as opposed to that with `*3`) works fine and is IMHO not half bad. – tobias_k Nov 25 '19 at 16:36
  • The last line imply to split/parse the input three time ;/ – mmeisson Nov 25 '19 at 16:40
  • @tobias_k sorry, I edited the post and left that sentence(before the edit there was no last line of code, just the two at the beginning) – Illic Nov 25 '19 at 16:59

3 Answers3

4

The pythonic way is "be explicit":

A = [int(a) for a in input().split()]
B = [int(a) for a in input().split()]
C = [int(a) for a in input().split()]

See The Zen of Python:

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.

Otherwise you could have a loop:

n = [[], [], []]
for i in range(3):
    n[i] += map(int, input().split())
A, B, C = n
Don
  • 16,928
  • 12
  • 63
  • 101
  • It would probably be much better to copy B and C from A instead of parsing input an other time. B = A.copy() – mmeisson Nov 25 '19 at 16:38
  • 1
    @mmeisson "I have a piece of code that gets 3 lists of integers from the user" it _should_ parse input three times. – tobias_k Nov 25 '19 at 16:38
  • @mmeisson I don't see any "given example", but it's literally the second sentence in the question. OP wants to get three lists of integers from _three different lines_ of input. – tobias_k Nov 25 '19 at 16:44
  • Yes, in fact that's what I want, get three different lists of ints in three separate lines. Sorry if I didn't make it clear. – Illic Nov 25 '19 at 16:54
  • 1
    Maybe I shouldn't ask for a "pythonic" way, maybe the words are "more elegant" way. – Illic Nov 25 '19 at 17:03
  • 1
    Personally, Don's answer is much more elegant than trying to cram 3 for loops and declaring 3 variables in one line. If anything, OP your first suggestion is pretty neat, except for the issue that the length of the line may get too long – alex067 Nov 25 '19 at 23:33
2

Don's answer gets to the heart of your question: don't feel like you need to use a single line for everything. However, one problem with your code is that you are using three separate variables A, B, and C where you should be using a single list or dict. In that sense, there is an elegant solution that uses one line:

results = {name: [int(a) for a input.split()] for name in ['A', 'B', 'C']}

However, this ignores a very real problem: that the user will enter data for which int will raise an exception. Depending on how you want to handle that, you should use a loop to wrap a try statement rather than call input three times from within the same expression.

results = {}
for name in ['A', 'B', 'C']:
    inp = input().split()
    results[name] = []
    for v in inp:
        try:
            v = int(v)
        except ValueError:
            v = 0
            # continue, if you want to skip that integer rather than pass
            # raise, if you really can't handle a non-integer input
        results[name].append(v)

If you really do just want to end the program early if any one input is not an integer, then you can go back to the one-liner wrapped in a try statement to exit gracefully.

try:
    results = {name: [int(a) for a input.split()] for name in ['A', 'B', 'C']}
except ValueError:
    sys.exit("Non-integer input detected, aborting")

In between these two extremes are lots of ways you can break the one-liner into smaller pieces that should either succeed or fail as a whole. For example,

results = {}
for name in ['A', 'B', 'C']:
    try:
        results[name] = [int(v) for v in input().split()]
    except ValueError:
        sys.exit(f"Inputs for {name} contained non-integer value, aborting")
chepner
  • 497,756
  • 71
  • 530
  • 681
  • *"you should be using a single list or dict"* That's not necessarily true, and it depends on the use case. If these variables serve different roles, and they would only ever be accessed with literal indices as `lst[0]`, `lst[1]` and `lst[2]`, then it's better to have them as separate variables. Consider the case of solving a quadratic equation: is `sqrt(b**2 - 4*a*c)` or `sqrt(lst[1]**2 - 4*lst[0]*lst[2])` better code? – kaya3 Nov 25 '19 at 17:48
  • 1
    Thank you! I love how elegant the dict solution looks and how easy it is to write code and have thought processes involving it. – Illic Nov 25 '19 at 17:52
  • 1
    @kaya3 If that's the case, you can always go back and write `A, B, C = lst` or `A, B, C = itemgetter("A", "B", "C")(dct)` after you've processed the input. Using a list/dict allows you to generalize the initialization of each with a loop. – chepner Nov 26 '19 at 01:28
  • "Simple is better than complex". I cannot recommend using a dict comprehension and `itemgetter`, when the task is simply to do something three times to declare three variables. – kaya3 Nov 26 '19 at 15:09
  • That was an example; write `A = dct["A"]`, etc if you like. – chepner Nov 26 '19 at 15:10
1

Declaring a function is a clean way to avoid reusing code by copy/paste.

def read_ints():
    return [ int(x) for x in input().split() ]

A = read_ints()
B = read_ints()
C = read_ints()
kaya3
  • 47,440
  • 4
  • 68
  • 97