0

I have a file in which I have some lines that looks like this:

[16, 1, 4, 15][0, 4, 5, 14][8, 9, 10, 3][2, 11, 12, 6][0, 1, 10, 11][1, 19, 12, 14][19, 3, 13, 15][9, 17, 14, 15][9, 2, 18, 17][8, 2, 13, 7][4, 2, 19, 12][16, 18, 3, 4][10, 3, 5, 15][16, 9, 18, 6][1, 19, 5, 7][0, 12, 6, 7][0, 17, 11, 13][16, 8, 18, 7][8, 17, 11, 13][10, 6, 5, 14]

and I want to read them, and make a list of lists with each line. I've tried split() function but does not work.

What I've tried is:

file = open(filename, 'r')
string.split(',')
print(string[3])

But it returns ,, not [2, 11, 12, 6]

Any guesses? Thanks in advance!

plr
  • 234
  • 1
  • 12

6 Answers6

3

You could use json and a list comprehension

import json
line = [16, 1, 4, 15][0, 4, 5, 14][8, 9, 10, 3][2, 11, 12, 6][0, 1, 10, 11][1, 19, 12, 14][19, 3, 13, 15][9, 17, 14, 15][9, 2, 18, 17][8, 2, 13, 7][4, 2, 19, 12][16, 18, 3, 4][10, 3, 5, 15][16, 9, 18, 6][1, 19, 5, 7][0, 12, 6, 7][0, 17, 11, 13][16, 8, 18, 7][8, 17, 11, 13][10, 6, 5, 14]
lst = [json.loads(sublist+']') for sublist in line.split(']') if sublist]

#[[16, 1, 4, 15],
# [0, 4, 5, 14],
# [8, 9, 10, 3],
# [2, 11, 12, 6],
# [0, 1, 10, 11],
# [1, 19, 12, 14],
# [19, 3, 13, 15],
# [9, 17, 14, 15],
# [9, 2, 18, 17],
# [8, 2, 13, 7],
# [4, 2, 19, 12],
# [16, 18, 3, 4],
# [10, 3, 5, 15],
# [16, 9, 18, 6],
# [1, 19, 5, 7],
# [0, 12, 6, 7],
# [0, 17, 11, 13],
# [16, 8, 18, 7],
# [8, 17, 11, 13],
# [10, 6, 5, 14]]

In this code, I split the line based on ']', this gives me a list of strings like '[16, 1, 4, 15', '[0, 4, 5, 14', ... Then for each of these strings, I add the ending bracket and use json to interpret it and transform it into a list.

Julien Spronck
  • 12,917
  • 2
  • 35
  • 45
2

In another website I get an answer which works (I don't know if it's a good way to do it, but it works for me).

A typical line in my file looks like this:

[16, 1, 4, 15][0, 4, 5, 14][8, 9, 10, 3][2, 11, 12, 6][0, 1, 10, 11][1, 19, 12, 14][19, 3, 13, 15][9, 17, 14, 15][9, 2, 18, 17][8, 2, 13, 7][4, 2, 19, 12][16, 18, 3, 4][10, 3, 5, 15][16, 9, 18, 6][1, 19, 5, 7][0, 12, 6, 7][0, 17, 11, 13][16, 8, 18, 7][8, 17, 11, 13][10, 6, 5, 14]

Is a string, not a list. And I want to make a list of lists from that str.

And my code now looks like this:

line=file.readline() # stores the str line from the file
line = '[' + line + ']'
line = line.replace('][', '],[')
line = ast.literal_eval(line)

Now I can access to each list within the (big) list, and each value in each list.

plr
  • 234
  • 1
  • 12
0

If string is the line that you gave above, a 1-line solution using a list comprehension is:

[[int(s) for s in t.split(',')] for t in string.strip()[1:-1].split('][')]

Like thus:

>>> string = '[16, 1, 4, 15][0, 4, 5, 14][8, 9, 10, 3][2, 11, 12, 6][0, 1, 10, 11][1, 19, 12, 14][19, 3, 13, 15][9, 17, 14, 15][9, 2, 18, 17][8, 2, 13, 7][4, 2, 19, 12][16, 18, 3, 4][10, 3, 5, 15][16, 9, 18, 6][1, 19, 5, 7][0, 12, 6, 7][0, 17, 11, 13][16, 8, 18, 7][8, 17, 11, 13][10, 6, 5, 14]\n'
>>> [[int(s) for s in t.split(',')] for t in string.strip()[1:-1].split('][')]
[[16, 1, 4, 15], [0, 4, 5, 14], [8, 9, 10, 3], [2, 11, 12, 6], [0, 1, 10, 11], [1, 19, 12, 14], [19, 3, 13, 15], [9, 17, 14, 15], [9, 2, 18, 17], [8, 2, 13, 7], [4, 2, 19, 12], [16, 18, 3, 4], [10, 3, 5, 15], [16, 9, 18, 6], [1, 19, 5, 7], [0, 12, 6, 7], [0, 17, 11, 13], [16, 8, 18, 7], [8, 17, 11, 13], [10, 6, 5, 14]]

This last is clearly a list of lists of integers, and not a string, as the following output shows:

>>> [sum(nums) for nums in [[int(s) for s in t.split(',')] for t in string.strip()[1:-1].split('][')]]
[36, 23, 30, 31, 22, 46, 50, 55, 46, 30, 37, 41, 33, 49, 32, 25, 41, 49, 49, 35]
John Coleman
  • 46,420
  • 6
  • 44
  • 103
  • I get this when I try to run it: `line 16, in [[int(s) for s in t.split(',')] for t in line[1:-1].split('][')] ValueError: invalid literal for int() with base 10: ' 14]' [Finished in 0.1s with exit code 1]` – plr Mar 13 '16 at 16:17
  • Try again -- I tweaked it to first strip off any trailing white space. – John Coleman Mar 13 '16 at 16:18
  • When I run try this, it returns a flat str, not a list. I'm going to try from this: http://stackoverflow.com/questions/1894269/convert-string-representation-of-list-to-list-in-python] to see if I can get something – plr Mar 13 '16 at 16:25
  • I am mystified by this last comment since I ran it on your posted string in both Python 2.7 and Python 3.4 and got a list of lists of integers both times. – John Coleman Mar 13 '16 at 16:51
  • I have added an answer which has worked for me. I think it's not the most efficient way to do it, because it differs a lot from what you have posted, but at least it works. I will try to use the answer you gave me, and if I get something, I`ll comment to you. Thanks! – plr Mar 13 '16 at 16:54
0
s='[16, 1, 4, 15][0, 4, 5, 14][8, 9, 10, 3][2, 11, 12, 6][0, 1, 10, 11][1, 19, 12, 14][19, 3, 13, 15][9, 17, 14, 15][9, 2, 18, 17][8, 2, 13, 7][4, 2, 19, 12][16, 18, 3, 4][10, 3, 5, 15][16, 9, 18, 6][1, 19, 5, 7][0, 12, 6, 7][0, 17, 11, 13][16, 8, 18, 7][8, 17, 11, 13][10, 6, 5, 14]'
[l.split(',') for l in s[1:-1].split('][')]
Raf
  • 946
  • 1
  • 10
  • 32
  • This returns a flat list rather than a list of lists and also seems to shave off the last character of the last number. – John Coleman Mar 13 '16 at 16:15
  • No flat list, list of lists. Corrected last char. – Raf Mar 13 '16 at 16:46
  • You are right about it not being a flat list -- but it gives a list of lists of strings rather than a list of list of ints. Concerning -1 vs. -2: it is probably best to first strip any white space rather than making any assumptions about its presence or absence. – John Coleman Mar 13 '16 at 16:54
0

If you do not want to use an extra module, you can do it with list comprehensions and string split and strip methods:

[[int(s.strip()) for s in sublist.split(',')] for sublist in line[1:-1].split('][')]

#[[16, 1, 4, 15],
# [0, 4, 5, 14],
# [8, 9, 10, 3],
# [2, 11, 12, 6],
# [0, 1, 10, 11],
# [1, 19, 12, 14],
# [19, 3, 13, 15],
# [9, 17, 14, 15],
# [9, 2, 18, 17],
# [8, 2, 13, 7],
# [4, 2, 19, 12],
# [16, 18, 3, 4],
# [10, 3, 5, 15],
# [16, 9, 18, 6],
# [1, 19, 5, 7],
# [0, 12, 6, 7],
# [0, 17, 11, 13],
# [16, 8, 18, 7],
# [8, 17, 11, 13],
# [10, 6, 5, 14]]
Julien Spronck
  • 12,917
  • 2
  • 35
  • 45
  • I tried it but it does not worked for me. I have posted an answer with the solution which has worked. (BTW, Should I mark my own answer as the correct one?, I'm very new here) – plr Mar 13 '16 at 16:49
  • I'm not sure of the point of the `strip` in `int(s.strip())` since `int` strips its input automatically. For example `int('\t \t23\t \n')` evaluates to `23`. A `strip` before `[1:-1]` might make sense if there is a `\n` at the end of the line. – John Coleman Mar 13 '16 at 17:03
0

The string you are reading is almost ready:

  • it needs an opening "["
  • commas between each list
  • and a closing "]"

just modify your string, that you have in a variable string as I see from your question, and then parse it with json.loads, or ast.literal_eval

import json # or ast
parse = json.loads
# or
# parse = ast.literal_eval

new_string = parse("".join(["[", string.replace("][", "],["), "]"])
chapelo
  • 2,244
  • 11
  • 18
  • How does this differ from the answer that OP posted 45 minutes earlier? – John Coleman Mar 13 '16 at 17:54
  • @JohnColeman: The main difference is that you don't need to iterate over every list and integer using loops or comprehensions, when you have the list of lists almost ready to parse as it is: you only need to wrap the string with "[ ]" and separate each sublist with commas, and then parse the whole line. No need to split every single element and reconstruct something that is almost done. – chapelo Mar 13 '16 at 18:26