Sort map by keys

I’ve been trying to fix some inconsistencies in an old image Shortcode I have, but I’ve reached I point I can’t go on. The whole code is enormous, so I’ll try to keep it simple.

One of the many things this Shortcode does is populate the srcset and sizes attributes for responsive images. Currently, I have this for the media queries used in the srcset:

{{ $queries := newScratch }}

{{ $queries.Set "1536"  "( min-width: 1536px )"   }}
{{ $queries.Set "1280"  "( min-width: 1280px )"   }}
{{ $queries.Set "1024"  "( min-width: 1024px )"   }}
{{ $queries.Set "992"   "( min-width: 992px )"    }}
{{ $queries.Set "768"   "( min-width: 768px )"    }}
{{ $queries.Set "640"   "( min-width: 640px )"    }}
{{ $queries.Set "576"   "( max-width: 409.98px )" }}

As you can see, they were all added from the largest viewport to the smallest. That’s how I learned responsive images work. The numeric keys will, later, be used to create a correspondence with the named Shortcode parameters so, as the current code goes, I can’t lose them.

But the output for this Scratch doesn’t respect the order:

map[1024:( min-width: 1024px ) 1280:( min-width: 1280px ) 1536:( min-width: 1536px ) 576:( max-width: 409.98px ) 640:( min-width: 640px ) 768:( min-width: 768px ) 992:( min-width: 992px )]

If I try to sort it, not only the result isn’t exactly what I would expect, but the keys are gone:

{{ $queries.Values "value" "desc" }}

[( min-width: 992px ) ( min-width: 768px ) ( min-width: 640px ) ( min-width: 1536px ) ( min-width: 1280px ) ( min-width: 1024px ) ( max-width: 409.98px )]

Reading the docs, I saw a (new?) getSortedMapValues that, perhaps, could help me, but I couldn’t make it work with this current structure because I don’t have a fixed, common key between all entries.

Any ideas on how I could solve this?

Curiously — and a bit off-topic — even out of order, Firefox pull images correctly while shrinking the viewport, but Chrome doesn’t.

When you access the map it is sorted by alphabetically by key in ascending order.

Key removal is expected when passing a map through the collections.Sort function.

Use a slice instead of a map:

{{ $s := slice
  (dict "width" 1536 "mediaQuery" "( min-width: 1536px )" )
  (dict "width" 1280 "mediaQuery" "( min-width: 1280px )" )
  (dict "width" 1024 "mediaQuery" "( min-width: 1024px )" )
  (dict "width" 992 "mediaQuery" "( min-width: 992px )" )
  (dict "width" 768 "mediaQuery" "( min-width: 768px )" )
  (dict "width" 640 "mediaQuery" "( min-width: 640px )" )
  (dict "width" 576 "mediaQuery" "( min-width: 409.98px )" )
}}

That gives you a data structure like this:

[
  {
    "mediaQuery": "( min-width: 1536px )",
    "width": 1536
  },
  {
    "mediaQuery": "( min-width: 1280px )",
    "width": 1280
  },
  {
    "mediaQuery": "( min-width: 1024px )",
    "width": 1024
  },
  {
    "mediaQuery": "( min-width: 992px )",
    "width": 992
  },
  {
    "mediaQuery": "( min-width: 768px )",
    "width": 768
  },
  {
    "mediaQuery": "( min-width: 640px )",
    "width": 640
  },
  {
    "mediaQuery": "( min-width: 409.98px )",
    "width": 576
  }
]

Yes, it is. I suggest you raise the question on Stack Overflow or similar.

2 Likes

I had to rewrite quite a lot of code to remove the Scratch dependency, but it worked flawlessly — though I wished a simple way to remove entries from slices by given offset existed, hehe

Thank you very much for your time :slight_smile:

You can retrieve a specific offset via collections.Index and then remove that retrieved item from the original collection via for instance collections.SymDiff. In general, have a look at all the collections methods. That is where the secret sauce hides.

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.