最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Iterate an object with reverse sorted keys - Stack Overflow

programmeradmin3浏览0评论

I know my question title can be confusing (I'm aware object properties don't have an order) since I'm already proposing a solution with it, so to avoid creating an XY problem, let me first explain my goal:

I need to render N tables of words grouped by word length and (this is the tricky thing) ordered by length in descending order . Something like:

Words with length 4
===================
abcd | other fields
abce | other fields 
abcf | other fields

Words with length 3
===================
abc  | other fields
abd  | other fields
abe  | other fields

Words with length 2
===================
...

I'm getting my list of words from an API without any grouping, so what I'm doing right now is:

let grouped = {};
// Assume words is an Array of words of multiple lengths
words.forEach(w => {
    if (typeof grouped[w.length] === 'undefined')
        grouped[w.length] = [];
    grouped[w.length].push({'word': w}); 
    // Pushing an object cause of other calculated and not rellevant fields
});

Of course, when I render this grouped words (I'm using Vue.js)...

<WordsTable 
    v-for="(group, length) in grouped"
    :words="group"
    :word-length="length"
/>

I use the word-length prop to render the table's header saying Words with length N.

Everything works but I get the tables in ascending order (and, again, I'm aware this might be a coincidence because there's no order in objects). So the real question is, can anybody figure out a way so that Vue iterates my grouped object with descending sorted keys?

Note: There might not be words of some specific lengths, so maybe Object.keys(grouped) is [3,4,7,9,10]

UPDATE:

A menter suggests using an Array instead of an Object for grouped. I already tried and it's true that might be slightly better but doesn't pletely solve the problem.

If grouped is an array, I can reverse it:

<WordsTable 
    v-for="(group, length) in grouped.reverse()"
    ...
/>

But in this case, indexes are lost and can no longer be used to render the table's header title.

I know my question title can be confusing (I'm aware object properties don't have an order) since I'm already proposing a solution with it, so to avoid creating an XY problem, let me first explain my goal:

I need to render N tables of words grouped by word length and (this is the tricky thing) ordered by length in descending order . Something like:

Words with length 4
===================
abcd | other fields
abce | other fields 
abcf | other fields

Words with length 3
===================
abc  | other fields
abd  | other fields
abe  | other fields

Words with length 2
===================
...

I'm getting my list of words from an API without any grouping, so what I'm doing right now is:

let grouped = {};
// Assume words is an Array of words of multiple lengths
words.forEach(w => {
    if (typeof grouped[w.length] === 'undefined')
        grouped[w.length] = [];
    grouped[w.length].push({'word': w}); 
    // Pushing an object cause of other calculated and not rellevant fields
});

Of course, when I render this grouped words (I'm using Vue.js)...

<WordsTable 
    v-for="(group, length) in grouped"
    :words="group"
    :word-length="length"
/>

I use the word-length prop to render the table's header saying Words with length N.

Everything works but I get the tables in ascending order (and, again, I'm aware this might be a coincidence because there's no order in objects). So the real question is, can anybody figure out a way so that Vue iterates my grouped object with descending sorted keys?

Note: There might not be words of some specific lengths, so maybe Object.keys(grouped) is [3,4,7,9,10]

UPDATE:

A menter suggests using an Array instead of an Object for grouped. I already tried and it's true that might be slightly better but doesn't pletely solve the problem.

If grouped is an array, I can reverse it:

<WordsTable 
    v-for="(group, length) in grouped.reverse()"
    ...
/>

But in this case, indexes are lost and can no longer be used to render the table's header title.

Share Improve this question edited Jul 10, 2018 at 11:32 Jordi Nebot asked Jul 10, 2018 at 11:01 Jordi NebotJordi Nebot 3,4093 gold badges31 silver badges60 bronze badges 2
  • You could store the words in an array instead of an object. Replace let grouped = {} by let grouped = [] – Weedoze Commented Jul 10, 2018 at 11:26
  • I tried. Doesn't work either. Let me update my question with more information. – Jordi Nebot Commented Jul 10, 2018 at 11:28
Add a ment  | 

3 Answers 3

Reset to default 5

You can create a puted property that sorts your object keys in a descending order:

sortedGroupKeys() { 
    return Object.keys( group ).sort( ( a , b ) => b - a ); 
}

then you can loop though it.

<WordsTable 
    v-for="(key in sortedGroupKeys)"
    :words="group[ key ]"
    :word-length="key"
/>

Hope this helps.

This should work. Iterate over a sorted list of the keys.

console.clear()

Vue.ponent("WordsTable",{
  props: ["words", "length"],
  template: `
    <table>
      <caption>Words of length {{length}}</caption>
      <tbody>
        <tr v-for="word in words"><td>{{word}}</td></tr>
      </tbody>
    </table>  
  `
})
new Vue({
  el: "#app",
  data:{
    words: [
      "hello", "apple", "mister", "wut", "phenomenal", "and", "vue", "four", "word"
    ]
  },
  puted:{
    grouped() {
      return this.words.reduce((groups, word) => {
        (groups[word.length] = groups[word.length] || []).push(word)
        return groups
      }, {})
    },
    sortedDesc(){
      return Object.keys(this.grouped).sort((a,b) => b - a)
    }
  }
})
caption {
 text-align: left;
 border-bottom: 1px solid black;
}

table {
  width: 10em;
  margin-bottom: 1em;
}
<script src="https://cdnjs.cloudflare./ajax/libs/vue/2.5.16/vue.min.js"></script>
<div id="app">
  <words-table v-for="length in sortedDesc" :key="length" :words="grouped[length]" :length="length"></words-table>
</div>

We can reverse the object using slice() and reverse().

Here the code I've applied to reverse the object:

v-for="edge in $static.posts.edges.slice().reverse()"
发布评论

评论列表(0)

  1. 暂无评论