简体   繁体   中英

Write two-dimensional list to JSON file

I have a two-dimensional list like:

data = [[1,2,3], [2,3,4], [4,5,6]]

I want to write it to JSON file like this:

{
    'data':[
        [1,2,3],
        [2,3,4],
        [4,5,6]
    ]
}

I get this with: json.dumps(data, indent=4, sort_keys=True) :

{
    'data':[
        [
         1,
         2,
         3
        ],
        [
         2,
         3,
         4
        ],
        [
         4,
         5,
         6]
    ]
}

Here is anther question How to implement custom indentation when pretty-printing with the JSON module? , but that's dictionaries.

I thought you could use my answer to another similar question to do what you want. While it works with json.dumps() , you pointed out that it doesn't for some reason with json.dump() .

After looking into the matter, I discovered that the encode() method of the derived json.JSONEncoder that was being overridden in the linked answer is only called when dumps() is called, but not when dump() is called.

Fortunately, I quickly was able to determine the iterencode() method does get invoked in both cases, so was able to fix the problem simply by more-or-less just moving the code from encode() and putting it into this other method instead.

The code immediately below is revised version with this change in it:

Modified version of the code in my answer to other question:

from _ctypes import PyObj_FromPtr  # see https://stackoverflow.com/a/15012814/355230
import json
import re


class NoIndent(object):
    """ Value wrapper. """
    def __init__(self, value):
        if not isinstance(value, (list, tuple)):
            raise TypeError('Only lists and tuples can be wrapped')
        self.value = value


class MyEncoder(json.JSONEncoder):
    FORMAT_SPEC = '@@{}@@'  # Unique string pattern of NoIndent object ids.
    regex = re.compile(FORMAT_SPEC.format(r'(\d+)'))  # compile(r'@@(\d+)@@')

    def __init__(self, **kwargs):
        # Keyword arguments to ignore when encoding NoIndent wrapped values.
        ignore = {'cls', 'indent'}

        # Save copy of any keyword argument values needed for use here.
        self._kwargs = {k: v for k, v in kwargs.items() if k not in ignore}
        super(MyEncoder, self).__init__(**kwargs)

    def default(self, obj):
        return (self.FORMAT_SPEC.format(id(obj)) if isinstance(obj, NoIndent)
                    else super(MyEncoder, self).default(obj))

    def iterencode(self, obj, **kwargs):
        format_spec = self.FORMAT_SPEC  # Local var to expedite access.

        # Replace any marked-up NoIndent wrapped values in the JSON repr
        # with the json.dumps() of the corresponding wrapped Python object.
        for encoded in super(MyEncoder, self).iterencode(obj, **kwargs):
            match = self.regex.search(encoded)
            if match:
                id = int(match.group(1))
                no_indent = PyObj_FromPtr(id)
                json_repr = json.dumps(no_indent.value, **self._kwargs)
                # Replace the matched id string with json formatted representation
                # of the corresponding Python object.
                encoded = encoded.replace(
                            '"{}"'.format(format_spec.format(id)), json_repr)

            yield encoded

Applying it to your question:

# Example of using it to do get the results you want.

alfa = [('a','b','c'), ('d','e','f'), ('g','h','i')]
data = [(1,2,3), (2,3,4), (4,5,6)]

data_struct = {
    'data': [NoIndent(elem) for elem in data],
    'alfa': [NoIndent(elem) for elem in alfa],
}

print(json.dumps(data_struct, cls=MyEncoder, sort_keys=True, indent=4))

# test custom JSONEncoder with json.dump()
with open('data_struct.json', 'w') as fp:
    json.dump(data_struct, fp, cls=MyEncoder, sort_keys=True, indent=4)
    fp.write('\n')  # Add a newline to very end (optional).

Output displayed (and resulting contents of the data_struct.json file):

{
    "alfa": [
        ["a", "b", "c"],
        ["d", "e", "f"],
        ["g", "h", "i"]
    ],
    "data": [
        [1, 2, 3],
        [2, 3, 4],
        [4, 5, 6]
    ]
}

You just need to add it to a empty dict as :

data = [[1,2,3], [2,3,4], [4,5,6]]
a = {}
a.update({"data":data})
print a

#{'data': [[1, 2, 3], [2, 3, 4], [4, 5, 6]]}

What you are trying in the 1st style is just a dict format. To get exact json from that dict You can add this dict to your json.dump to dump the file.

For json format you just need to dump it as :

import json
b = json.dumps(a)
print b
#{"data": [[1, 2, 3], [2, 3, 4], [4, 5, 6]]}

You can go to pro.jsonlint.com and check whether the json format is correct or not.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM