0

I have a file containing numerical values:

1
4
6
10
12

and I'm trying to append these values into its respective position in an array where i would obtain:

[None,1,None,None,4,None,6,None,None,None,10,None,None,12]

Since 1 from the file would be at index 1 in the list, 4 from the file would be at index 4 in the list and so on.

I begin by first reading in the file:

filename = open("numbers.txt", "r", encoding = "utf-8")
numfile = filename

lst = [None] * 12

for line in numfile:
    line = line.strip()   #strip new line
    line = int(line)       #making the values in integer form  

    vlist.append(line)   #was thinking of line[val] where value is the number itself.
print(vlist)

but I'm getting the output:

[None,None,None,None,None,None,None,None,None,1,4,6,10,12]

Where the numbers are appended to the far right of the array. Would appreciate some help on this.

Maxxx
  • 3,688
  • 6
  • 28
  • 55

4 Answers4

2

Assuming you have your number as integers in a list called numbers (which you have no problem doing as it seems), you can do:

lst = [None if i not in numbers else i for i in range(max(numbers)+1)]

if numbers can be a big list, I would cast it to set first to make the in comparisons faster.

numbers = set(numbers)
lst = [None if i not in numbers else i for i in range(max(numbers)+1)]

Example

>>> numbers = [1, 4, 6, 10, 12]
>>> [None if i not in numbers else i for i in range(max(numbers) + 1)]
[None, 1, None, None, 4, None, 6, None, None, None, 10, None, 12]
Ma0
  • 15,057
  • 4
  • 35
  • 65
  • Nice I need to pratice about the pythonic style, I'm too used of using regular programming structures – Cid May 16 '18 at 09:48
  • If this `[None, 1, None, None, 4, None, 6, None, None, None, 10, None, None]` is expected, your code might not work – Cid May 16 '18 at 09:50
  • @Cid You do seem to have a Fortran background ☺. That is a good thing though! – Ma0 May 16 '18 at 09:50
  • @Cid But this is not what is expected.. What do you mean by that? – Ma0 May 16 '18 at 09:51
  • If his file contains `[1, 4, 6, 10]` and he expects a 13-sized list as shown in the OP example – Cid May 16 '18 at 09:52
  • I started with C, not Fortran :) – Cid May 16 '18 at 09:53
  • @Cid Oh, I see. But my understanding is that the size of the list depends on the largest number in the file. – Ma0 May 16 '18 at 09:53
0

Appending to a list adds the numbers at the end of the list. You instead want to assign the value of line to the list at the index of line

filename = open("numbers.txt", "r", encoding = "utf-8")
numfile = filename

lst = [None] * 13

for line in numfile:
    line = line.strip()   #strip new line
    line = int(line)       #making the values in integer form  
    lst[line] = line  

print(lst)
# [None, 1, None, None, 4, None, 6, None, None, None, 10, None, 12]
DavidG
  • 24,279
  • 14
  • 89
  • 82
0

Appending to a list in a loop is expensive. I advise your construct a list of None items and then iterate your list to update elements.

Below is a demo with itertools and csv.reader:

from io import StringIO
from itertools import chain
import csv

mystr = StringIO("""1
4
6
10
12""")

# replace mystr with open('numbers.txt', 'r')
with mystr as f:
    reader = csv.reader(f)
    num_list = list(map(int, chain.from_iterable(reader)))

res = [None] * (num_list[-1]+1)

for i in num_list:
    res[i] = i

print(res)

[None, 1, None, None, 4, None, 6, None, None, None, 10, None, 12]

Benchmarking example:

def appender1(n):
    return [None]*int(n)

def appender2(n):
    lst = []
    for i in range(int(n)):
        lst.append(None)
    return lst

%timeit appender1(1e7)  # 90.4 ms per loop
%timeit appender2(1e7)  # 1.77 s per loop
jpp
  • 159,742
  • 34
  • 281
  • 339
  • Don't you have to append to a list when you build num_list? How can that be more efficient than initializing `res` before opening the file, and just setting one element of `res` for each line in the file? – Paul Cornelius May 16 '18 at 09:49
  • @PaulCornelius, See my benchmarking example. You only know the length of your list *after* reading the file. So you can use `num_list[-1]` to get the last element (the largest, since your example assumes ordering) and use this to calculate the length. – jpp May 16 '18 at 09:52
  • Of course appending one at a time is much slower than allocating the whole array at once. It seems there's some doubt about how to interpret the question - OP started by declaring an array of None's (but didn't make it big enough to include element with an index of 12). You're assuming that the values in the file are sorted. Your guess is definitely as good as mine :-) – Paul Cornelius May 16 '18 at 10:01
  • It's not so much that `list.append` in a loop is expensive (it's not, relatively speaking, it is an optimized amortized constant time operation), but that looping at the python interpreter level is much slower than looping at the C-level, which list-repetition does. – juanpa.arrivillaga May 16 '18 at 10:01
  • @juanpa.arrivillaga, Thank your insight, yep I do understand that the issue is with Python interpreter overhead of a `for` loop vs C loop, I wasn't trying to pin it down to `list.append`. – jpp May 16 '18 at 10:04
0

You can use an indexer and compare its value with the actual value of the line, and replace the value at the index rather than

filename = open("numbers.txt", "r", encoding = "utf-8")
numfile = filename

lst = [None] * 12
i = 0
for line in numfile:
    line = line.strip()   #strip new line
    line = int(line)       #making the values in integer form  
    value = None
    if (i == line):
        value = line
    if (len(vlist) < line): #replace or append if there's more numbers in the file than the size of the list
        vlist[i] = value
    else:
        vlist.append(value) 
    i += 1
print(vlist)
Cid
  • 14,968
  • 4
  • 30
  • 45