sorting selected items in an array (javascript) - javascript

I have got an array that contains data in hierarchical form such as:
Level 2
chapter 1
chapter 2
Level 4
chapter 1
chapter 2
Level 1
chapter 1
chapter 2
Level 3
chapter 1
chapter 2
If I just call array.sort(), the hierarchy gets disturbed. So, I have to develop my own way of sorting items. The thing I can't understand is, how would I compare two levels such that I would know that level 1 is less than level 2 and it should be at the top index of the array?

You really shouldn't be using a flat array. You lose all the hierarchical information. Something like this would be better:
//I've deliberately made these unsorted to show you that sorting works
levels = ["Level 4", "Level 3", "Level 1", "Level 2"];
data = {
"Level 3" : ["chapter 1", "chapter 2"],
"Level 1" : ["chapter 2", "chapter 1"],
"Level 2" : ["chapter 2", "chapter 1"],
"Level 4" : ["chapter 1", "chapter 2"]
};
levels.sort();
for(var i = 0 i < levels.length; i++) {
console.log(levels[i]);
var chapters = data[levels[i]];
chapters.sort();
for(var j = 0; j < chapters.length; j++) {
console.log(chapters[j]);
}
}
EDIT
Rob suggested using levels.sort(function(x,y){return x.localeCompare(y)}) instead of the regular .sort(). The former will sort ["abc", "Abcd", "Ab"] to ["Ab", "abc", "Abcd"] instead of ["Ab", "Abcd", "abc"].

This should reformat the flat PHP array to the nicer JS object:
var fromPHP = ['Level 2','chapter 1','chapter 2','Level 4','chapter 1','chapter 2','Level 1','chapter 1','chapter 2','Level 3','chapter 1','chapter 2'];
var levels = [],
betterArray = [fromPHP[0]],
currentLevel=betterArray[0];
for (var i=1;i<fromPHP.length;i++) {
if (fromPHP[i].substr(0,5) == 'Level') {
currentLevel = [];
levels.push(fromPHP[i]);
betterArray[fromPHP[i]] = currentLevel;
} else {
currentLevel.push(fromPHP[i]);
}
}
Should give the following levels and betterArray:
// levels:
['Level 4','Level 3','Level 1','Level 2']
// betterArray:
{
'Level 2': ['chapter 1','chapter 2'],
'Level 4': ['chapter 1','chapter 2'],
'Level 1': ['chapter 1','chapter 2'],
'Level 3': ['chapter 1','chapter 2']
}
Now you can run whatever sorting you want on the subarrays and get what you wanted.

Related

Concatenate two columns of an array into a new one

I have the array range with 3 columns and 10 rows.
How can I concatenate the contents of column 1 with column 2 and push them to a new range dataEnome?
I'm using the following loop, but it isn't very efficient:
var dataEnome =[];
for (i=0; i<range.length; i++){
dataEnome.push(range[i][0])+(range[i][1]);
};
The range looks like this:
For data mapping you can consider using the array.map API.
Example:
var range =
[
[ 'col1.a', 'col2.1', 'c' ],
[ 'col1.b', 'col2.2', '3' ],
[ 'col1.c', 'col2.3', '6' ],
[ 'col1.d', 'col2.4', '9' ],
[ 'col1-e', 'col2.5', '1c' ],
[ 'col1-f', 'col2.6', '6c' ],
[ 'col1-g', 'col2.7', '7c' ],
[ 'col1-h', 'col2.8', '8c' ],
[ 'col1-i', 'col2.9', '9c' ],
[ 'col1-j', 'col2.10', '0c' ],
];
var dataEnome =range.map(row => { return row[0] + row[1]});
console.log(dataEnome);
For more example usages for map;
See:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
If you want to concatenate each record from both column
You may do something like this:
var dataEnome =[];
for (i=0; i<range.getValues().length; i++){
dataEnome.push(range.getValues()[i][0]+range.getValues()[i][1]);
};
Hope this will help you.
Thanks.
... besides dataEnome.push(range[i][0])+(range[i][1]); does most probably feature a broken syntax ...
shouldn't it be dataEnome.push(range[i][0] + range[i][1]); or dataEnome.push(range[i][0].concat(range[i][1]));
... I do not consider the OP's solution to be not that efficient.
One only could transform it into a reusable and more functional style ...
function collectConcatenatedFirstTwoRowColumns(collector, row) {
collector.push(row[0].concat(" / ", row[1]));
return collector;
}
var
range = [
["0, 0", "0, 1", "0, 2"],
["1, 0", "1, 1", "1, 2"],
["2, 0", "2, 1", "2, 2"],
["3, 0", "3, 1", "3, 2"],
["4, 0", "4, 1", "4, 2"],
["5, 0", "5, 1", "5, 2"]
],
dataEnome = range.reduce(collectConcatenatedFirstTwoRowColumns, []);
console.log(dataEnome);

remove first element from array and return the array minus the first element

var myarray = ["item 1", "item 2", "item 3", "item 4"];
//removes the first element of the array, and returns that element.
alert(myarray.shift());
//alerts "item 1"
//removes the last element of the array, and returns that element.
alert(myarray.pop());
//alerts "item 4"
How to remove the first array but return the array minus the first element
In my example i should get "item 2", "item 3", "item 4" when i remove the first element
This should remove the first element, and then you can return the remaining:
var myarray = ["item 1", "item 2", "item 3", "item 4"];
myarray.shift();
alert(myarray);
As others have suggested, you could also use slice(1);
var myarray = ["item 1", "item 2", "item 3", "item 4"];
alert(myarray.slice(1));
Why not use ES6?
var myarray = ["item 1", "item 2", "item 3", "item 4"];
const [, ...rest] = myarray;
console.log(rest)
Try this
var myarray = ["item 1", "item 2", "item 3", "item 4"];
//removes the first element of the array, and returns that element apart from item 1.
myarray.shift();
console.log(myarray);
This can be done in one line with lodash _.tail:
var arr = ["item 1", "item 2", "item 3", "item 4"];
console.log(_.tail(arr));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
myarray.splice(1) will remove the first item from the array … and return the updated array (['item 2', 'item 3', 'item 4'] in your example).
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice
array = [1,2,3,4,5,6,7,8,9];
array2 = array.slice(1,array.length); //arrayExceptfirstValue
console.log(array2);
I over through all the notable answers. I am pointing out a different answer. It works for me. I hope it will help you
array.slice(1,array.length)
You can use array.slice(0,1) // First index is removed and array is returned.

Array with levels - each level has values

I'm trying to create an array that has multiple levels and multiple values on each level. It needs to look something like this:
Value 1 level 1
Value 1 level 2
Value 1 level 3
Value 2 level 2
Value 2 level 1
How can I put something like this in an array?
You can make each level as a new array.
var myArray = new Array("Value 1 level 1", "Value 2 level 1");
myArray['Value 1 level 1'] = new Array("Value 1 level 2", "Value 2 level 2");
myArray['Value 2 level 2'] = new Array("Value 1 level 3");
you can have an array of objects like the below structure
var value=
{
value1level1:
{
value1level2:
{
value1level3:'somevalue'
}
}
};
var parentObj=[value];
Create a JSON structure like this:
[
{
"node":{
"Value 1":"level 1"
},
"children":[
{
"node":{
"Value1":"level 2"
},
"children":[
{
"node":{
"Value1":"level 3"
},
"children":[
]
}
]
}
]
},
{
"node":{
"Value 2":"level 1"
},
"children":[
]
}
]

How to group javascript object properties based on a portion of the key name?

How do I loop over this javascript object structure to group each key by it's index. For example mobile_1 and desktop_1 should be grouped.
Each _1 should be together, and _2. and so on.
Here is the object:
{
"mobile_1": "source/test.jpg",
"mobile_2": "source/test.jpg",
"mobile_3": "source/test.jpg",
"desktop_1": "source/test.jpg",
"desktop_2": "source/test.jpg",
"desktop_3": "source/test.jpg",
"link_1": "#",
"link_2": "#",
"link_3": "#",
"tag_1": "Test 1",
"tag_2": "Test 2",
"tag_3": "Test 3",
"linkLabel_1": "Test 1 Go",
"linkLabel_2": "Test 2 Go",
"linkLabel_3": "Test 3 Go",
"title_1": "Test 1 Desc",
"title_2": "Test 2 Desc",
"title_3": "Test 3 Desc"
}
Is there an easy way to group these keys by a portion of the key name?
My guess is that you were putting group each key, by it's _# suffix, into a "group object".
First, iterate over each member and find a way to pull the suffix you're looking for. Regex is perfect for this application.
for(var key in src){
var key.match(/_\d/);
// ...
Next, get well versed in bracket notation. It allows you to "dynamically" access an attribute by a string or string variable; as well as further child objects.
// assume suffix==="_1" and key==="mobile_1" <-- Still in the for-loop
group[suffix][key] = src[key];
/* ^- Same as group["_1"]["mobile_1"] = src["mobile_1"];
^- Same as group._1.mobile_1 = "source/test.jpg"
^- Same as group = { "_1": { "mobile_1": "source/test.jpg" }};
*/
Working example:
var group = { };
src = {
"mobile_1": "source/test.jpg",
"mobile_2": "source/test.jpg",
"mobile_3": "source/test.jpg",
"desktop_1": "source/test.jpg",
"desktop_2": "source/test.jpg",
"desktop_3": "source/test.jpg",
"link_1": "#",
"link_2": "#",
"link_3": "#",
"tag_1": "Test 1",
"tag_2": "Test 2",
"tag_3": "Test 3",
"linkLabel_1": "Test 1 Go",
"linkLabel_2": "Test 2 Go",
"linkLabel_3": "Test 3 Go",
"title_1": "Test 1 Desc",
"title_2": "Test 2 Desc",
"title_3": "Test 3 Desc"
}
for(var key in src){
var suffix = key.match(/_\d/);
// The following will create the new "group" in the
// master group variable if it doesn't exist
if(!group[suffix]){ group[suffix] = {}; }
group[suffix][key] = src[key];
}
console.log(group); //grouped objects printed to log
alert(JSON.stringify(group) ); //sent to alert box so snippet runs.

Automatically generate names in a javascript array

I have been struggling a lot with a piece of javascript code recently. The code looks like this:
var bigData = {
"teams" : [
["Team 1", "Team 2" ],
["Team 3", "Team 4" ],
["Team 5", "Team 6" ],
["Team 7", "Team 8" ],
["Team 9", "Team 10" ],
["Team 11", "Team 12" ],
["Team 13", "Team 14" ],
["Team 15", "Team 16" ],
],
results : [[ /* WINNER BRACKET */
[[1,0], [1,0], [0,3], [2,3], [1,5], [5,3], [7,2], [1,2]],
[[1,2], [3,4], [5,6], [7,8]],
[[9,1], [8,2]],
[[1,3]]
]
}
As you might have guessed, it's a jquery plugin for tournaments. The problem is that I don't want to write the teams manually, I want them to be written automatically I have done this, and the code doesn't work, because the while loop is inside the variable (so far I know) :
var count = 1;
var bigData = {
"teams" : [
while (count <= 8) {
["Team ".count, "Team ".count ],
count++;
}
],
results : [[ /* WINNER BRACKET */
[[1,0], [1,0], [0,3], [2,3], [1,5], [5,3], [7,2], [1,2]],
[[1,2], [3,4], [5,6], [7,8]],
[[9,1], [8,2]],
[[1,3]]
]
}
It won't work, and I really don't know what to do.
var bigData = {
"teams" : [],
results : [[ /* WINNER BRACKET */
[[1,0], [1,0], [0,3], [2,3], [1,5], [5,3], [7,2], [1,2]],
[[1,2], [3,4], [5,6], [7,8]],
[[9,1], [8,2]],
[[1,3]]
]] };
for( var i=1 ; i<16 ; i+=2 )
bigData.teams.push(['Team '+i,'Team '+(i+1)]);
console.log(JSON.stringify(bigData));
In console:
{"teams":[["Team 1","Team 2"],["Team 3","Team 4"],["Team 5","Team 6"],["Team 7","Team 8"],["Team 9","Team 10"],["Team 11","Team 12"],["Team 13","Team 14"],["Team 15","Team 16"]],"results":[[[[1,0],[1,0],[0,3],[2,3],[1,5],[5,3],[7,2],[1,2]],[[1,2],[3,4],[5,6],[7,8]],[[9,1],[8,2]],[[1,3]]]]}
Try this:
var count = 1;
var data = [];
while (count <= 16) {
data.push(["Team " + (count++).toString(), "Team " + count.toString() ]);
count++;
}
var bigData = {
"teams" : data
}
It builds the array by pushing the teams into it. Note the concatenation of count as a string to the team name, plus the ++ on the first count to iterate it to the next team (thus producing Team 1 and Team 2, not Team 1 and Team 1).
and the code doesnt work, because the while loop is inside the variable
Yes, you cannot put control flow statements in the midst of an object literal. Instead, you will need to start with an empty array, and then fill that with values via assignments (or push):
var teams = [];
for (var i=1; i<=16; )
teams.push(['Team '+i++,'Team '+i++]);
var bigData = {
teams: teams,
results: …
};
The other answers provided here build a list of teams using a set number (8, 16, whatever).
You can get a little cheeky and generate the list of teams off the teams in the actual results instead, which will future-proof your script against your league size expanding. Code spends most of its lifetime in maintenance, if you can spend just a few extra minutes to make your stuff more data-driven, you'll save plenty of time over the long haul.
Since you're using jquery, I'll make some use of the functions in that library here:
var bigData = {
results : [
[ /* WINNER BRACKET */
[[1,0], [1,0], [0,3], [2,3], [1,5], [5,3], [7,2], [1,2]],
[[1,2], [3,4], [5,6], [7,8]],
[[9,1], [8,2]],
[[1,3]]
]
]
};
function flatten(n) {
return $.map(n, function(x){
return $.isArray(x) ? flatten(x) : x;
});
}
bigData.teams = $.map(
$.unique(flatten(bigData.results)).sort(),
function(num) { return "Team "+num; }
);
Console output:
> JSON.stringify(bigData)
"{
"results":[[[[1,0],[1,0],[0,3],[2,3],[1,5],[5,3],[7,2],[1,2]],[[1,2],[3,4],[5,6],[7,8]],[[9,1],[8,2]],[[1,3]]]],
"teams":["Team 0","Team 1","Team 2","Team 2","Team 2","Team 3","Team 4","Team 5","Team 6","Team 7","Team 8","Team 8","Team 9"]
}"

Categories

Resources