-2

I have this C++

int n = 0;
file >> n;

for (int i = 0; i < n; i++) file >> array[i];

etc.

How do i write it succinctly in Python?

This is Python:

string = string.lstrip()

n = 0
for c in string:
  if not c.isdigit():
    break
  n = n * 10 + int(c)

for i in range(n):
  string = string.lstrip()
  for c in string:
    if not c.isdigit():
      break
    array[i] = array[i] * 10 + int(c)

I thought Python was supposed to be more "expressive" than C++.

2 Answers2

2

The io class tells us what methods a file object has (the thing returned by open()). I do not see anything like "read word" or "read int".

I was going to say it's simple to write some small functions that do that, but it turned into a 4-hour expedition and became rather large to be just an example in a Stack Overflow answer. I've posted it on Github instead: https://github.com/lgommans/OpenSesame

The file you need is just open_sesame.py. Basic usage is:

from open_sesame import OpenSesame

myfile = OpenSesame("data.txt")
records = myfile.int()
for i in range(0, records):
    array.append(myfile.number())

I tried commenting the code and making it quite clear, so it should be understandable if you want to make modifications or see what it does.

Luc
  • 5,339
  • 2
  • 48
  • 48
1

Don't parse integers from strings manually. Python is perfectly capable of doing that for you:

>>> s = "12345"
>>> i = int(s)
>>> print(i)
12345

That already cleans up a substantial part of your code:

string = string.lstrip()
n = int(string)

for i in range(n):
  string = string.lstrip()
  array[i] = int(string)

I don't see any logic that moves around the string, so I assume you have left those pieces out. You aren't explicit about what exactly it is that separates these integers either (your code says "anything that isn't a digit"), so I'll assume instead it's whitespace-delimited.

Python can split such strings for you through one of the methods in str: split.

>>> s = "1 2\n3\t4 5"  # Notice: all kinds of whitespace here.
>>> arr = s.split()  # By default, split will split on whitespace.
>>> print(arr)
['1', '2', '3', '4', '5']

Notice that the split leaves the values as strings. That means we aren't done yet, we also have to convert each individual element into an integer as I demonstrated before.

Here, I'll use a Python feature called list comprehensions:

>>> s = "1 2\n3\t4 5"
>>> arr = [int(n) for n in s.split()]
>>> print(arr)
[1, 2, 3, 4, 5]

This is what people are talking about when they mention the "expressiveness" of Python :) This turns all of the code you've written into a one-liner. However, this assumes your data is in a string already. It seems you're reading from a file, so there's a bit more work required to get it working properly...

arr = []  # Empty list. 
with open("path/to/file.txt") as f:
    for line in f:  # Will read all lines.
        arr += [int(x) for x in line.split()]
# Use arr...

...which assumes you have multiple ints in a line. If instead you have a single int on every line, your code becomes much simpler:

with open("path/to/file.txt") as f:
    arr = [int(line) for line in f]  # Will read all lines.
# Use arr...

However, this still isn't a complete solution to your original problem... But I hope it's educational regardless. FWIW, this is how I would solve your particular problem:

with open("path/to/file.txt") as f:
    ints_of_f = (int(line) for line in f)  # A *GENERATOR*, not a *LIST*.
    n = next(ints_of_f)
    arr = [next(ints_of_f) for _ in range(n)]  # _ is a throwaway variable.

Finally, here's a great talk on how to write "beautiful, expressive" Python code.

Brian Rodriguez
  • 4,250
  • 1
  • 16
  • 37
  • Accualy when you have multiple lines you don't have to iterate over them like `for line in file`, you can just `read` the whole file. If you want to go all in: `arr = (lambda it: [next(it) for _ in range(next(it))])(map(int, open(FILENAME).read().split()))` How['](http://i1.kym-cdn.com/entries/icons/original/000/000/091/cancer.png)s that for expressiveness? –  Apr 05 '17 at 01:20
  • Expressiveness to me is readability, not number of characters/lines :) And yes, it's true that you can `.read()` the whole file, just beware of using it on very big files. – Brian Rodriguez Apr 05 '17 at 01:31
  • It would be nice if there was some read-iterator, that wouldn't require reading the file up front and instead would read when needed like a standard generator. –  Apr 05 '17 at 01:35
  • 1
    There is! It's called [mmap](http://stackoverflow.com/a/454589/4859885) ;) – Brian Rodriguez Apr 05 '17 at 01:45
  • Does that work on windows? (Seems it does, somewhat) (But on linux I get [Errno 12] Permission denied) [SOLVED] `mmap.mmap(f.fileno(), 0, prot=mmap.PROT_READ)` Thanks. –  Apr 05 '17 at 01:56