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 = {}
bylet 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
3 Answers
Reset to default 5You 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()"