Skip to content

Header order  #40

Closed
Closed

Description

@danja100

Header order defined by the order that keys are discovered, rather than the order that they are present in.

E.g.

from collections import OrderedDict
from tabulate import tabulate

test_dict = [
        OrderedDict([("a", 1), ("b", 2), ("e", 5)]),
        OrderedDict([("a", 1), ("b", 2), ("c", 3), ("d", 4), ("e", 5)]),
    ]

print(tabulate(
    test_dict, headers="keys", tablefmt="simple", missingval="0"
))

gives the output:

  a    b    e    c    d
---  ---  ---  ---  ---
  1    2    5    0    0
  1    2    5    3    4

whereas I would prefer it in this order:

  a    b    c    d    e
---  ---  ---  ---  ---
  1    2    0    0    5
  1    2    3    4    5

Activity

  1. astanin commented on Mar 5, 2020

    @astanin
    Owner

    This behavior is by design. Reason 1: It's easier to check the first element of a data set, and immediately have an idea how the data will be printed. Reason 2: If some attributes are optional, it's conventional to display them as the last columns of a table, most important information comes first. Reason 3: Existing logic is easier to understand, implement and define unambiguously (otherwise, how sequences "abc", "edab" and "bad" are supposed to me merged? there is no guarantee that all elements have keys sorted in the same way).

    A workaround is to add missing values to the first dictionary. Tabulate has to fill missing values anyway. Keys of the first OrderedDict will allow to define a specific order of columns.

    default = OrderedDict([(k,None) for k in "abcde"])
    default.update(test_dict[0])
    test_dict[0] = default
    print(tabulate(
        test_dict, headers="keys", tablefmt="simple", missingval="0"
    ))
    

    Another workaround is to pre-process data and reorder columns:

    order = "abcde"
    print(tabulate([[r.get(k,0) for k in order] for r in test_dict], headers=order))
    

    There is another important reason not to implement this feature: it will break the documented behavior (pull request #41 is breaking existing tests). At this point we cannot exclude that some users are relying on that.

    Considering that an alternative to breaking changes is just a line of code, I would rather keep the library as is.

  2. danja100 commented on Mar 5, 2020

    @danja100
    ContributorAuthor

    Fair enough. Thanks for the workarounds, I'll take a look at using these.

    (apologies, ignore the latest commit, I realised I hadn't configured the test but hadn't seen your reply)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    wontfixThis will not be worked on

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions