0

I have following dictionary:

map = {'`s_h_o_seq_id`': 'STRING', '`s_h_o_identifier`': 'STRING', '`c`': 'STRING', '`c_system`': 'STRING', '`c_system_name`': 'STRING', '`display_name`': 'STRING', '`original_text`': 'STRING', '`status_c`': 'STRING', '`efc_time_high`': 'STRING', '`efc_time_low`': 'STRING', '`efc_time_v`': 'STRING', '`v_type`': 'STRING', '`v_text`': 'STRING', '`v_unit`': 'STRING', '`v_c`': 'STRING', '`v_c_system`': 'STRING', '`v_c_system_name`': 'STRING', '`v_c_display_name`': 'STRING', '`ctd_by`': 'STRING', '`ctd_date`': 'STRING', '`updtd_by`': 'STRING', '`updtd_date`': 'STRING', '`is_deleted`': 'STRING', '`pat_practice_id`': 'STRING', '`release`': 'STRING', '`section_name`': 'STRING', '`parent_entity_name`': 'STRING', '`class_c`': 'STRING', '`com_mood_c`': 'STRING', '`t_id_root`': 'STRING', '`t_id_extn`': 'STRING'}

I tried to obtain its list of its entries sorted by keys as follows:

print(sorted(map.items(), key=lambda kv: (kv[0])))

This prints:

[('`c_system_name`', 'STRING'), ('`c_system`', 'STRING'), ('`c`', 'STRING'), ('`class_c`', 'STRING'), ('`com_mood_c`', 'STRING'), ('`ctd_by`', 'STRING'), ('`ctd_date`', 'STRING'), ('`display_name`', 'STRING'), ('`efc_time_high`', 'STRING'), ('`efc_time_low`', 'STRING'), ('`efc_time_v`', 'STRING'), ('`is_deleted`', 'STRING'), ('`original_text`', 'STRING'), ('`parent_entity_name`', 'STRING'), ('`pat_practice_id`', 'STRING'), ('`release`', 'STRING'), ('`s_h_o_identifier`', 'STRING'), ('`s_h_o_seq_id`', 'STRING'), ('`section_name`', 'STRING'), ('`status_c`', 'STRING'), ('`t_id_extn`', 'STRING'), ('`t_id_root`', 'STRING'), ('`updtd_by`', 'STRING'), ('`updtd_date`', 'STRING'), ('`v_c_display_name`', 'STRING'), ('`v_c_system_name`', 'STRING'), ('`v_c_system`', 'STRING'), ('`v_c`', 'STRING'), ('`v_text`', 'STRING'), ('`v_type`', 'STRING'), ('`v_unit`', 'STRING')]

Consider first three tuples in the above output list:

('`c_system_name`', 'STRING'), ('`c_system`', 'STRING'), ('`c`', 'STRING')

I wanted them in exactly reverse order, that is:

('`c`', 'STRING'), ('`c_system`', 'STRING'), ('`c_system_name`', 'STRING')

So I tried to get rid of those single quotes in keys, just in case they were causing trouble:

sorted_map = sorted(map.items(), key=lambda kv: (kv[0][1:len(kv)-1]))

The output was:

[('`s_h_o_seq_id`', 'STRING'), ('`s_h_o_identifier`', 'STRING'), ('`c`', 'STRING'), ('`c_system`', 'STRING'), ('`c_system_name`', 'STRING'), ('`display_name`', 'STRING'), ('`original_text`', 'STRING'), ('`status_c`', 'STRING'), ('`efc_time_high`', 'STRING'), ('`efc_time_low`', 'STRING'), ('`efc_time_v`', 'STRING'), ('`v_type`', 'STRING'), ('`v_text`', 'STRING'), ('`v_unit`', 'STRING'), ('`v_c`', 'STRING'), ('`v_c_system`', 'STRING'), ('`v_c_system_name`', 'STRING'), ('`v_c_display_name`', 'STRING'), ('`ctd_by`', 'STRING'), ('`ctd_date`', 'STRING'), ('`updtd_by`', 'STRING'), ('`updtd_date`', 'STRING'), ('`is_deleted`', 'STRING'), ('`pat_practice_id`', 'STRING'), ('`release`', 'STRING'), ('`section_name`', 'STRING'), ('`parent_entity_name`', 'STRING'), ('`class_c`', 'STRING'), ('`com_mood_c`', 'STRING'), ('`t_id_root`', 'STRING'), ('`t_id_extn`', 'STRING')]

But this seems to mess up everything (keys 's...' appear before 'c...'):

('`s_h_o_seq_id`', 'STRING'), ('`s_h_o_identifier`', 'STRING'), ('`c`', 'STRING')

Why I am getting above output and how can I get what I desire?

Mahesha999
  • 22,693
  • 29
  • 116
  • 189
  • 2
    Possible duplicate of [How can I sort a dictionary by key?](https://stackoverflow.com/questions/9001509/how-can-i-sort-a-dictionary-by-key) – Kunal Mukherjee May 14 '19 at 10:33
  • 1
    nope...I knew I can use `sorted()` which is what is answered in that question. My question is why its not working for me / for my set of keys, what mistake I am doing. And I was indeed doing silly mistake of having `len(kv)` instead of `len(kv[0])` as you can read in comments and answers below. – Mahesha999 May 14 '19 at 10:57

2 Answers2

4

The problem here is not the sorting, but the contents of your keys. Those backticks also count when sorting, and the backtick is sorted after underscores, but before lower-case letters:

>>> sorted(["`", "a", "_"])
['_', '`', 'a']

This is why "`c_system_name`" sorts before "`c_system`", because the '`' backtick character at the end of "`c_system`" sorts after the underscore at the same position in "`c_system_...`".

Sort without backticks:

sorted(map.items(), key=lambda kv: kv[0].strip("`"))

or don't create keys with backticks around their value.

Demo:

>>> print(sorted(map.items(), key=lambda kv: kv[0].strip("`")))
[('`c`', 'STRING'), ('`c_system`', 'STRING'), ('`c_system_name`', 'STRING'), ('`class_c`', 'STRING'), ('`com_mood_c`', 'STRING'), ('`ctd_by`', 'STRING'), ('`ctd_date`', 'STRING'), ('`display_name`', 'STRING'), ('`efc_time_high`', 'STRING'), ('`efc_time_low`', 'STRING'), ('`efc_time_v`', 'STRING'), ('`is_deleted`', 'STRING'), ('`original_text`', 'STRING'), ('`parent_entity_name`', 'STRING'), ('`pat_practice_id`', 'STRING'), ('`release`', 'STRING'), ('`s_h_o_identifier`', 'STRING'), ('`s_h_o_seq_id`', 'STRING'), ('`section_name`', 'STRING'), ('`status_c`', 'STRING'), ('`t_id_extn`', 'STRING'), ('`t_id_root`', 'STRING'), ('`updtd_by`', 'STRING'), ('`updtd_date`', 'STRING'), ('`v_c`', 'STRING'), ('`v_c_display_name`', 'STRING'), ('`v_c_system`', 'STRING'), ('`v_c_system_name`', 'STRING'), ('`v_text`', 'STRING'), ('`v_type`', 'STRING'), ('`v_unit`', 'STRING')]

The str.strip() method is a much better way of removing the backticks than using slicing, because it'll remove zero or more backticks from start and end, and leave other characters alone.

Your own attempt with kv[0][1:len(kv)-1] was using the wrong len(); len(kv) is always 2, you wanted len(kv[0]). Not that you ever need to calculate the length in slicing, as negative slices already count from the end: kv[0][1:-1] removes the first and last characters.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
1

You should change len(kv) to len(kv[0]):

sorted_map = sorted(map.items(), key=lambda kv: (kv[0][1:len(kv[0])-1]))
sanyassh
  • 8,100
  • 13
  • 36
  • 70