Additional keys were returned from `getStaticPaths` - javascript

I'm working on Next JS project with getStaticPaths. I want to fetch blogs and activities on a page, but it wouldn't work.
I am trying to create paths multiplied by each slug by turning the map again inside the map in getStaticPaths.
const getActivityEntries = async () => {
const { items }: EntryCollection<IActivityFields> =
await client.getEntries({
content_type: 'activity',
})
return items
}
const getBlogEntries = async () => {
const { items }: EntryCollection<IBlogFields> =
await client.getEntries({
content_type: 'blog',
})
return items
}
export const getStaticPaths: GetStaticPaths = async () => {
const activities = await getActivityEntries()
const blogs = await getBlogEntries()
const paths = activities
.filter((activity) => activity.fields.slug !== undefined)
.map((activity) => {
return blogs
.filter((blog) => blog.fields.slug !== undefined)
.map((blog) => {
return {
params: {
slug: blog.fields.slug as string,
activitySlug: activity.fields.slug as string,
},
}
})
})
return {
paths,
fallback: false,
}
}
And the error below occurs when I try to access a blog link :
Error: Additional keys were returned from `getStaticPaths` in page "/blogs/[slug]/activities/[activitySlug]". URL Parameters intended for this dynamic route must be nested under the `params` key, i.e.:
return { params: { slug: ..., activitySlug: ... } }
Keys that need to be moved: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69.

Related

How to add class to selected element in React Js

I have numbers in my list and I am displaying them on the board:
const numbers = [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75,
];
{numbers.map(number, index) => (
<div className="bingo-grid__row" id={index+1} key={index}>
<div className={className}>
<div className="bingo-ball bingo-ball">
<div className="bingo-ball__text">{number}</div>
</div>
</div>
</div>
)
}
Besides that, I am selecting a random number:
const [chosen, setChosen] = useState(null);
const [selectedNumbers, setSelectedNumbers] = useState([]);
const chooseNumber = () => {
let r;
do {
r = Math.floor(Math.random() * 75) + 1;
}
while (selectedNumbers.indexOf(r) > -1)
setChosen(r)
setSelectedNumbers([...selectedNumbers, r]);
};
And what I am trying to do is add a class if the number is matching with the random number. So for example, if the random number is 6, I want to add a new class to the bingo-grid__row. Any suggestion for this?
You can create the class dynamically by adding a condition like this:
{numbers.map( (number, index) => (
<div className={`bingo-grid__row ${chosen === number ? yourClassToAdd : ""}`} id={index+1} key={index}>
//rest of the logic
)
}
Update:
If you want to keep the selections persistent then you can change the condition to use the selectedNumbers state that you already created like this:
{numbers.map( (number, index) => (
<div className={`bingo-grid__row ${selectedNumbers.includes(number) ? yourClassToAdd : ""}`} id={index+1} key={index}>
//rest of the logic
)
}
const [chosen, setChosen] = useState(null);
const [selectedNumbers, setSelectedNumbers] = useState([]);
const chooseNumber = async () => {
let r;
let component = document.querySelector(".bingo-grid__row")
do {
r = await Math.floor(Math.random() * 75) + 1;
if(r === 6){
componet.classList.add("newClass")
}
}
while (selectedNumbers.indexOf(r) > -1)
setChosen(r)
setSelectedNumbers([...selectedNumbers, r]);
};

How to make dynamic variable to check array with .every

For a project we need to check if all numbers in a card, match another card with drawn numbers.
When hardcoded with a const checkCard = card001 it goes well with .every.
When trying to choose the card a dynamic way, pulling the number from a localStorage (e.g. const card = 'card'+cardNumber), an error pops up with t.every is not a function.
The question: how to make this dynamic. We hope someone is able to help to overcome this issue.
checkCard = () => {
var cardNumber = localStorage.cardNumber;
const card001 = [14, 4, 10, 8, 12, 30, 28, 23, 16, 27, 41, 35, 43, 39, 53, 57, 46, 48, 56, 74, 68, 75, 70, 66]
const card002 = [15, 13, 8, 1, 12, 26, 20, 19, 28, 24, 38, 42, 33, 41, 59, 53, 60, 55, 51, 68, 62, 71, 70, 65]
const card003 = [11, 5, 4, 13, 9, 23, 27, 16, 18, 26, 44, 38, 40, 36, 53, 47, 56, 55, 50, 69, 65, 63, 61, 74]
const previousCallList = JSON.parse(JSON.stringify(this.previousCallList));
console.log('previousCallList: ', previousCallList)
const previousCallListNumber = JSON.parse(JSON.stringify(this.previousCallListNumber));
console.log('previousCallListNumber: ', previousCallListNumber)
//const card = 'card'+cardNumber;
const checkCard = card001
const checkDrawn = previousCallListNumber ;
const containsAll = checkCard .every(element => {
return checkDrawn.includes(element);
});
console.log(containsAll); // 👉️ true
}
}
There's a difference between these two lines:
// Point `checkCard` to the current array stored in `card001`
const checkCard = card001
// Point `checkCard` to a string "card001"
const checkCard = "card001"
When you write 'card'+cardNumber, you're creating a new string, not a reference to another variable.
If you want to dynamically pick a variable based on its name, you can define named properties on an object. For example:
const myObject = {
a: 1,
b: 2,
c: 3
};
console.log(
myObject["a"],
myObject["b"],
myObject["c"]
)
Or, with your data:
const cardNumber = "001";
const card001 = [14, 4, 10, 8, 12, 30, 28, 23, 16, 27, 41, 35, 43, 39, 53, 57, 46, 48, 56, 74, 68, 75, 70, 66]
const card002 = [15, 13, 8, 1, 12, 26, 20, 19, 28, 24, 38, 42, 33, 41, 59, 53, 60, 55, 51, 68, 62, 71, 70, 65]
const card003 = [11, 5, 4, 13, 9, 23, 27, 16, 18, 26, 44, 38, 40, 36, 53, 47, 56, 55, 50, 69, 65, 63, 61, 74]
const cardVarName = "card" + cardNumber;
log(cardVarName); // This is now the string "card001", not a reference to the card001 variable
// Store the cards in an object
const cards = { card001, card002, card003 };
// Reference a card using obj[propertyName]
log(cards[cardVarName])
function log(x) { console.log(JSON.stringify(x)); }
If you intend to use localStorage you need to familiarize yourself with the syntax, what you have now...
localStorage.cardNumber;
...should've given you an error. The following are two functions that get and set data to and from localStorage:
/*
>key< is a string assigned as an id to stored data.
If there isn't anything stored an empty array is returned/
*/
const getLS = key => JSON.parse(localStorage.getItem(key)) || [];
/*
>key< is same as above. >data< is the value that needs to
be stored.
*/
const setLS = (key, data) => localStorage.setItem(key, JSON.stringify(data));
Note that LS only stores strings which is why JSON.parse() and JSON.stringify() are used on the data. In the example the
lines concerning LS are commented out because SO snippets prohibit them -- just uncomment them when you test them in a normal environment.
Details are commented in example below
// Utility function
const log = data => console.log(JSON.stringify(data));
//const getLS = key => JSON.parse(localStorage.getItem(key)) || [];
//const setLS = (key, data) => localStorage.setItem(key, JSON.stringify(data));
/*
All arrays as parameters so function can be reusable
*/
const deckA = [14, 4, 10, 8, 12, 30, 28, 23, 16, 27, 41, 35, 43, 39, 53, 57, 46, 48, 56, 74, 68, 75, 70, 66];
const deckB = [15, 13, 8, 1, 12, 26, 20, 19, 28, 24, 38, 42, 33, 41, 59, 53, 60, 55, 51, 68, 62, 71, 70, 65];
const deckC = [11, 5, 4, 13, 9, 23, 27, 16, 18, 26, 44, 38, 40, 36, 53, 47, 56, 55, 50, 69, 65, 63, 61, 74];
/**
* find match between a given number and a
* number from one or more given arrays
* #param {number} card = Number to find
* #param {arrays} cards = One or more arrays
* #returns {array<object>} Each object is
* created like this:
* {card: 55, row: 2, col: 17}
* "card 55 is in the 3rd array index 17"
*/
const findMatch = (card, ...cards) => {
//const data = getLS('cards');
//data.push(card);
//setLS('cards', data);
// Gather ...cards into an array:
// [ [deckA], [deckB], [deckC] ]
const decks = [...cards];
/*
First, .map() runs through each sub-array and
.flatMap() compares each number of each sub-
array vs. card. If there's a match, return
a new object (see above) otherwise an empty
array is returned
*/
return decks.map((sub, row) => sub.flatMap((num, col) => num === card ? {card: card, row: row, col: col} : [])).flat();
};
log(findMatch(55, deckA, deckB, deckC));
log(findMatch(3, deckA, deckB, deckC));
log(findMatch(25, deckA, deckB, deckC));
log(findMatch(13, deckA, deckB, deckC));

Iterate between specific range of number in a array [duplicate]

This question already has answers here:
Create array of all integers between two numbers, inclusive, in Javascript/jQuery
(21 answers)
Closed 3 years ago.
I have an array with two elements [5, 50]. I want this array iterate as [5, 6, 7,......, 49, 50].
I try below code. But not working as my expectation.
function All(arr) {
let newArry = [];
for(let i = arr[0]; i < arr[1]; i++ ) {
newArry[i] = newArry.push(i);
}
return newArry;
}
console.log(All([5, 50]));
Do like this remove newArry[i] =
function All(arr) {
let newArry = [];
for(let i = arr[0]; i < arr[1]; i++ ) {
newArry.push(i);
}
return newArry;
}
console.log(All([5, 50]));
Get the two values you want to iterate between:
const [start, end] = [5, 50];
Create a new array of length difference between your two points:
Array(end - start + 1) // [undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined]
Since all the values will be undefined, create an iterator object using Array#keys: Array(end - start + 1).keys() // [object Array Iterator]
Spread that into an array:
[...Array(end - start + 1).keys()] // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45]
Map over the values to create your new array:
[...Array(end - start + 1).keys()].map(i => i + start) // [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50]
...which gives you something like this:
const range = (n, m) => [...Array(m - n + 1).keys()].map(i => i + n);
const [start, end] = [5, 50];
console.log(range(start, end)); // [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50]
Or, to maintain the API of the function in your question, like this:
const All = (arr) => {
const [n, m] = arr;
return [...Array(m - n + 1).keys()].map(i => i + n);
}
console.log(All([5, 50])); // [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50]
The Array.prototype.push method mutates the original array, so reassigning doesn't make sense.
Just do:
newArray.push(i);

Changing an array in place using splice()

I'm trying to write a function that, given an array and n, returns the array with elements repeating no more than n times. I cannot change the order of the array.
Below is the code I have so far. What is perplexing me is that it works for most elements in a given array, but not for some others. I'm trying to find a rhyme or reason for the elements for which the code does not work.
function deleteNth(arr,n){
arr.forEach(function (item, index) {
var count = 0;
for (var i = 0; i < arr.length; i++) {
if (arr[i] === item) {
count++;
while (count > n) {
var remove = arr.lastIndexOf(item);
arr.splice(remove, 1);
count--;
}
}
}
});
return arr;
}
var x = deleteNth([7, 26, 21, 41, 43, 2, 26, 24, 10, 26, 10, 10, 24, 35, 35,
35, 43, 26, 41, 7, 24, 24, 21, 24, 10, 35, 10, 7, 24, 7, 35, 26, 41,
35, 2, 43, 24, 2, 41, 26, 41, 7, 7, 26, 2, 10, 43, 10, 35, 41, 24, 7,
2, 2, 7, 2, 26, 24, 26, 43, 43, 21, 10, 28, 10], 2);
console.log(x);
Currently returns this...
[7, 26, 21, 41, 43, 2, 26, 24, 10, 10, 10, 24, 35, 35, 43, 41, 7, 21,
41, 2, 43, 28]
But I should get this...
[7, 26, 21, 41, 43, 2, 26, 24, 10, 10, 24, 35, 35, 43, 41, 7, 21, 2,
28]
Any insight into where I'm going wrong would be sincerely appreciated.
The logic of where you places the while loop is wrong, you need to place it outside of the for loop.
function deleteNth(arr, n) {
arr.forEach(function(item, index) {
var count = 0;
for (var i = 0; i < arr.length; i++) {
if (arr[i] === item) {
count++;
}
}
while (count > n) {
var remove = arr.lastIndexOf(item);
arr.splice(remove, 1);
count--;
}
});
return arr;
}
var x = deleteNth([7, 26, 21, 41, 43, 2, 26, 24, 10, 26, 10, 10, 24, 35, 35,
35, 43, 26, 41, 7, 24, 24, 21, 24, 10, 35, 10, 7, 24, 7, 35, 26, 41,
35, 2, 43, 24, 2, 41, 26, 41, 7, 7, 26, 2, 10, 43, 10, 35, 41, 24, 7,
2, 2, 7, 2, 26, 24, 26, 43, 43, 21, 10, 28, 10
], 2);
console.log(x);
Why? Because when you are doing your loop and you remove things from it, you shift things back down. So when you have two items side by side and you remove the first the second one shifts down one spot to fill what you just removed. The i does not change so you do not check the item that just filled the gap.
What would I do? I would just keep track of the items as I get to it and if I have not gone over the max append it.
function cleanUp (arr, max) {
const cnts = {} // keep track of what we find
return arr.reduce((a, i) => { // loop over the array index by index
cnts[i] = (cnts[i] || 0) + 1; // mark that I seen the number
if (cnts[i] <= max) { // check to see if we are under the max
a.push(i) //if we are, add it to an arry
}
return a // return the array for reduce
}, [])
}
console.log(cleanUp([7, 26, 21, 41, 43, 2, 26, 24, 10, 26, 10, 10, 24, 35, 35,
35, 43, 26, 41, 7, 24, 24, 21, 24, 10, 35, 10, 7, 24, 7, 35, 26, 41,
35, 2, 43, 24, 2, 41, 26, 41, 7, 7, 26, 2, 10, 43, 10, 35, 41, 24, 7,
2, 2, 7, 2, 26, 24, 26, 43, 43, 21, 10, 28, 10], 2))
This code works:
function deleteNth(arr,n){
var rem = new Array(), new_arr = new Array();
arr.forEach(function (item, index) {
if(!rem[item]) rem[item]=0;
if(rem[item]<n){
new_arr.push(item);
rem[item]++;
}
});
return new_arr;
}
console.log(deleteNth([7, 26, 21, 41, 43, 2, 26, 24, 10, 26, 10, 10, 24, 35, 35, 35, 43, 26, 41, 7, 24, 24, 21, 24, 10, 35, 10, 7, 24, 7, 35, 26, 41, 35, 2, 43, 24, 2, 41, 26, 41, 7, 7, 26, 2, 10, 43, 10, 35, 41, 24, 7, 2, 2, 7, 2, 26, 24, 26, 43, 43, 21, 10, 28, 10], 2));
All of your code is true. Just bring that while out of for loop.
function deleteNth(arr, n) {
arr.forEach(function(item, index) {
var count = 0;
for (var i = 0; i < arr.length; i++) {
if (arr[i] === item) {
count++;
}
}
while (count > n) {
var remove = arr.lastIndexOf(item);
arr.splice(remove, 1);
count--;
}
});
return arr;
}
var x = deleteNth([7, 26, 21, 41, 43, 2, 26, 24, 10, 26, 10, 10, 24, 35, 35,
35, 43, 26, 41, 7, 24, 24, 21, 24, 10, 35, 10, 7, 24, 7, 35, 26, 41,
35, 2, 43, 24, 2, 41, 26, 41, 7, 7, 26, 2, 10, 43, 10, 35, 41, 24, 7,
2, 2, 7, 2, 26, 24, 26, 43, 43, 21, 10, 28, 10
], 2);
console.log(x);
I like Nina's filter (probably performs better as well) but you can also use reduce:
function deleteNth(arr,n){
return arr.reduce(
([result,map],item)=>{
const count = (map.get(item)||0)+1;
return [
//do not add if more than n of this item have been added already
(count<=n)?result.concat(item):result,
map.set(item,count)//set the new count for this item and return map
]
},
[[],new Map()]//initial value for result and map
)[0];
}
Here is an example using filter and a Map:
function deleteNth(arr,n){
const map = new Map();
return arr.filter(
item=>{
const count = (map.get(item)||0)+1;
map.set(item,count);
return (count<=n);
}
);
}
console.log(deleteNth([1,2,3,2,4,2,5], 2));
If you really want to do it in place, then this answer is not for you. (I think there are very good reasons to work with immutable data, but if you want to mutate, one of the other answers should do it.
Here's one solution that simply keeps a count of each item seen as you go, and filters out those we've seen too often:
const deleteNth = (arr, n) => {
const found = new Map()
return arr.filter(val => {
found.set(val, (found.get(val) || 0) + 1)
return found.get(val) <= n
})
}
const result = deleteNth([7, 26, 21, 41, 43, 2, 26, 24, 10, 26, 10, 10, 24, 35, 35, 35, 43, 26, 41, 7, 24, 24, 21, 24, 10, 35, 10, 7, 24, 7, 35, 26, 41, 35, 2, 43, 24, 2, 41, 26, 41, 7, 7, 26, 2, 10, 43, 10, 35, 41, 24, 7, 2, 2, 7, 2, 26, 24, 26, 43, 43, 21, 10, 28, 10], 2)
console.log(result)
One other note: It might offer a nicer API if you choose:
deleteNth = (n) => (arr) => { /* ... */ }
This way you could pass just the repetition count and get back a new function which filters an array.
(Also, this does not sound like a good name for something that delete's all repetitions of a value after the nth one.)
For a fast mutating version, you could use a single while loop, a hash table for counting the items and an adjustment of the index if a splice happens.
function deleteNth(array, n) {
var counter = Object.create(null),
i = 0, v;
while (i < array.length) {
v = array[i];
if (!counter[v]) {
counter[v] = 0;
}
if (++counter[v] > n) {
array.splice(i, 1);
continue;
}
i++;
}
return array;
}
console.log(deleteNth([7, 26, 21, 41, 43, 2, 26, 24, 10, 26, 10, 10, 24, 35, 35, 35, 43, 26, 41, 7, 24, 24, 21, 24, 10, 35, 10, 7, 24, 7, 35, 26, 41, 35, 2, 43, 24, 2, 41, 26, 41, 7, 7, 26, 2, 10, 43, 10, 35, 41, 24, 7, 2, 2, 7, 2, 26, 24, 26, 43, 43, 21, 10, 28, 10], 2));
.as-console-wrapper { max-height: 100% !important; top: 0; }
A better way is to use filter and return a new array.
function deleteNth(array, n) {
var counter = Object.create(null);
return array.filter(v => (counter[v] = (counter[v] || 0) + 1) <= n);
}
console.log(deleteNth([7, 26, 21, 41, 43, 2, 26, 24, 10, 26, 10, 10, 24, 35, 35, 35, 43, 26, 41, 7, 24, 24, 21, 24, 10, 35, 10, 7, 24, 7, 35, 26, 41, 35, 2, 43, 24, 2, 41, 26, 41, 7, 7, 26, 2, 10, 43, 10, 35, 41, 24, 7, 2, 2, 7, 2, 26, 24, 26, 43, 43, 21, 10, 28, 10], 2));
.as-console-wrapper { max-height: 100% !important; top: 0; }

how to match array of ids to object properties that contains their id as part of the property name

I have a object that has had a section_id added to the property names.
"price_min-3155": 54,
"price_min-12863": 23,
"price_min-16152": 43, etc...
I have a array of the section_ids
var sectionIdArray = [3155,12863,16152];
also in the object i have the property subdivision_id which needs to stay as is.
"subdivision_id": 3500,
the end result i am looking is grouping the properties by the section_id and also including the subdivision_id. need to have object array that looks like this.
newArry = [{
subdivision_id: 3500,
section_id: 3155, //"section_id-3155": 3155,
price_min:54, //"price_min-3155": 54,
price_max: 34, // "price_max-3155": 34,
units_occ: 54, //"units_occ-3155": 54,
etc...
},{
subdivision_id: 3500,
section_id: 12863, //"section_id-12863": 12863,
price_min:23, //"price_min-12863": 23,
price_max: 56, // "price_max-12863": 56,
units_occ: 9, //"units_occ-12863": 9,
etc...
}]
javascript,jquery,lodash and linq.js are all good. here is working plunker
working plunker
$scope.model = {
"section_id-3155": 3155,
"price_min-3155": 54,
"units_total-3155": 323,
"price_max-3155": 34,
"units_occ-3155": 54,
"inv_mod-3155": 5,
"inv_fin-3155": 6,
"inv_vdl-3155": 35,
"inv_uc-3155": 45,
}
This should do it:
var data = {
"section_id-3155": 3155,
"price_min-3155": 54,
"units_total-3155": 323,
"price_max-3155": 34,
"units_occ-3155": 54,
"inv_mod-3155": 5,
"inv_fin-3155": 6,
"inv_vdl-3155": 35,
"inv_uc-3155": 45,
"inv_fut-3155": 45,
"inv_con-3155": 45,
"fs_excav-3155": true,
"fs_streets-3155": true,
"fs_stakes-3155": true,
"section_id-12863": 12863,
"subdivision_id": 3500,
"price_min-12863": 23,
"price_max-12863": 56,
"units_occ-12863": 9,
"inv_mod-12863": 32,
"inv_fin-12863": 56,
"inv_vdl-12863": 123,
"inv_uc-12863": 54,
"inv_fut-12863": 76,
"inv_con-12863": 23,
"units_total-12863": 87,
"$$hashKey-12863": "object:60",
"section_id-16152": 16152,
"price_min-16152": 43,
"units_total-16152": 994,
"price_max-16152": 9,
"units_occ-16152": 65,
"inv_mod-16152": 765,
"inv_fin-16152": 34,
"inv_vdl-16152": 65,
"inv_uc-16152": 6,
"inv_fut-16152": 7,
"fs_excav-12863": true,
"fs_paved-12863": true,
"fs_equip-12863": true,
"fs_stakes-12863": true,
"fs_equip-16152": true,
"fs_excav-16152": true,
"fs_paved-16152": true,
"fs_streets-16152": true
};
var sectionIdArray = [3155, 12863, 16152];
var objectArray = sectionIdArray.map(function(id) {
var res = {
subdivision_id: data.subdivision_id
};
Object.keys(data).forEach(function(key) {
var regex = new RegExp("-" + id + "$");
if (regex.test(key)) {
res[key.replace(regex, "")] = data[key];
}
});
return res;
});
//output
document.body.innerHTML = JSON.stringify(objectArray);
Here is what I done using lodash. This works fine with your sample data but can be modified to conform to more strict rules. It is just an example how it can be done with lodash.
$scope.model = {
"section_id-3155": 3155,
"price_min-3155": 54,
"units_total-3155": 323,
"price_max-3155": 34,
"units_occ-3155": 54,
"inv_mod-3155": 5,
"inv_fin-3155": 6,
"inv_vdl-3155": 35,
"inv_uc-3155": 45,
"inv_fut-3155": 45,
"inv_con-3155": 45,
"fs_excav-3155": true,
"fs_streets-3155": true,
"fs_stakes-3155": true,
"section_id-12863": 12863,
"subdivision_id": 3500,
"price_min-12863": 23,
"price_max-12863": 56,
"units_occ-12863": 9,
"inv_mod-12863": 32,
"inv_fin-12863": 56,
"inv_vdl-12863": 123,
"inv_uc-12863": 54,
"inv_fut-12863": 76,
"inv_con-12863": 23,
"units_total-12863": 87,
"$$hashKey-12863": "object:60",
"section_id-16152": 16152,
"price_min-16152": 43,
"units_total-16152": 994,
"price_max-16152": 9,
"units_occ-16152": 65,
"inv_mod-16152": 765,
"inv_fin-16152": 34,
"inv_vdl-16152": 65,
"inv_uc-16152": 6,
"inv_fut-16152": 7,
"fs_excav-12863": true,
"fs_paved-12863": true,
"fs_equip-12863": true,
"fs_stakes-12863": true,
"fs_equip-16152": true,
"fs_excav-16152": true,
"fs_paved-16152": true,
"fs_streets-16152": true
};
$scope.res = {};
var res = _($scope.model)
.pairs()
.groupBy(function (val) {
var parts = val[0].split('-');
return parts[parts.length-1];
})
.transform(function (result, val, key, src) {
if (!isNaN(key)) { // is number
key = +key;
result[key] = _(val)
.zipObject()
.transform(function (result, val, key) {
var parts = key.split('-'), newKey;
parts.splice(-1, 1);
newKey = parts.join('-');
result[newKey] = val;
}, {})
.value();
result[key]['subdivision_id'] = src['subdivision_id'][0][1];
}
}, {})
.value();
$scope.res = res;
I also updated your plunker.
i will give you an idea of a possible abstract algorithm:
iterate over all keys k in $scope.model (for var key in $scope.model) { ...}
in each step iterate over every value v in the sectionIdArray
if v is part of the string k (k.indexOf(v) !== -1) then put it into such a "basket" (eg an array correlated to this sectionId)
for every basket create a new entry for your result-array by evaluating the data there (getting min/max etc) and copying the subvision_id from the original object
if you have any more question about this algorithm don't hesitate to ask, but don't expect me to implement the whole algorithm for you ;)
You can use a temporary object and make then the wanted array.
var data = { "section_id-3155": 3155, "price_min-3155": 54, "units_total-3155": 323, "price_max-3155": 34, "units_occ-3155": 54, "inv_mod-3155": 5, "inv_fin-3155": 6, "inv_vdl-3155": 35, "inv_uc-3155": 45, "inv_fut-3155": 45, "inv_con-3155": 45, "fs_excav-3155": true, "fs_streets-3155": true, "fs_stakes-3155": true, "section_id-12863": 12863, "subdivision_id": 3500, "price_min-12863": 23, "price_max-12863": 56, "units_occ-12863": 9, "inv_mod-12863": 32, "inv_fin-12863": 56, "inv_vdl-12863": 123, "inv_uc-12863": 54, "inv_fut-12863": 76, "inv_con-12863": 23, "units_total-12863": 87, "section_id-16152": 16152, "price_min-16152": 43, "units_total-16152": 994, "price_max-16152": 9, "units_occ-16152": 65, "inv_mod-16152": 765, "inv_fin-16152": 34, "inv_vdl-16152": 65, "inv_uc-16152": 6, "inv_fut-16152": 7, "fs_excav-12863": true, "fs_paved-12863": true, "fs_equip-12863": true, "fs_stakes-12863": true, "fs_equip-16152": true, "fs_excav-16152": true, "fs_paved-16152": true, "fs_streets-16152": true },
keys = Object.keys(data),
result = keys.reduce(function (r, k) {
var p = k.split('-'), o;
if (p[1]) {
if (!(p[1] in r.temp)) {
o = { subdivision_id: data['subdivision_id'] };
r.a.push(o);
r.temp[p[1]] = o;
}
r.temp[p[1]][p[0]] = data[k];
}
return r;
}, { temp: {}, a: [] }).a;
document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');

Categories