Related
I am required to write a function that receives an array of numbers and
should return the array sorted using for the comparison of their last digit, if their last digit is the same you should check the second to last and so on.
Example:
Input: [1, 10, 20, 33, 13, 60, 92, 100, 21]
Output: [100, 10, 20, 60, 1, 21, 92, 13, 33]
but I get
Output: [ 10, 20, 60, 100, 1, 21, 92, 33, 13 ]
my code:
/**I guess the input numbers are only integers*/
input = [1, 10, 20, 33, 13, 60, 92, 100, 21];
const reverseString = (string) => {
const stringToArray = string.split("");
const reversedArray = stringToArray.reverse();
const reversedString = reversedArray.join("");
return reversedString;
};
let sortedInput = input.sort((firstNumber, secondNumber) => {
const firstNumberReversed = reverseString(firstNumber.toString());
const secondNumberReversed = reverseString(secondNumber.toString());
const largerOne = Math.max(
firstNumberReversed,
secondNumberReversed
).toString;
for (let i = 0; i < largerOne.length; i++) {
if (firstNumberReversed[i] != secondNumberReversed[i]) {
if(firstNumberReversed[i] > secondNumberReversed[i]){
return 1
}
if(secondNumberReversed[i] > firstNumberReversed[i]){
return -1
}
}
}
});
console.log(sortedInput);
You can achieve this result if you sort it after reversing the number
const arr = [1, 10, 20, 33, 13, 60, 92, 100, 21];
const result = arr
.map((n) => [n, n.toString().split("").reverse().join("")])
.sort((a, b) => a[1].localeCompare(b[1]))
.map((a) => a[0]);
console.log(result);
You can do this using the Remainder Operator:
Demo:
const data = [1, 10, 20, 33, 13, 60, 92, 100, 21];
data.sort((a, b) => {
for (let i = 1, sum = a + b; ; i *= 10) {
const diff = (a % i) - (b % i);
if (diff === 0 && i < sum) continue;
return diff;
}
});
console.log(data);
I have an array of object, which every object contain a section and a data;
const arr = [
{ section: "a", data: [1, 2] },
{ section: "b", data: [3, 4, 5, 6] },
{ section: "c", data: [7, 8, 9, 10, 11, 12, 13] }
];
Now I want to paginate it.
I need to display 4 item in one page.
So it would be like:
[
{page: 1, section: ['a', 'b'], data: [1, 2, 3, 4]}
{page: 2, section: ['b', 'c'], data: [5, 6, 7, 8]}
{page: 3, section: ['c'], data: [9, 10, 11, 12]}
{page: 4, section: ['c'], data: [13]}
]
Any help, I tried many ways but still could not solve.
My Efforts
const arr = [
{ title: "a", data: [1, 2] },
{ title: "b", data: [3, 4, 5, 6] },
{ title: "c", data: [7, 8, 9, 10, 11, 12, 13] }
];
let c = 0, na = [], ha = [];
for(let i = 0; i < arr.length; i++){
let ia = arr[i].data;
for(let k = 0; k < ia.length; k++){
na = [...na, [ arr[i].title, ia[k] ]];
// na = [...na, {[c]: {section: arr[i].title, data: ia[k]}}]; c++;
}
}
// console.log(JSON.stringify(na));
function chunk (arr, len) {
var chunks = [], i = 0, n = arr.length;
while (i < n) {
chunks.push(arr.slice(i, i += len));
}
return chunks;
}
const resCh = chunk(na, 3);
console.log(resCh);
let finalArr = [];
for(let i = 0; i< resCh.length; i++){
let nstd = resCh[i], finalObj = {};
nstd.reduce( (t, s) => {
if(t[0] === s[0]) {
if(finalObj[t[0]]){
finalObj = {
...finalObj,
[t[0]]: [
...finalObj[t[0]],
t[1], s[1]
]
}
}else {
finalObj = {
...finalObj,
[t[0]]: [t[1], s[1]]
}
}
}else {
if(finalObj[t[0]]){
finalObj = {
...finalObj,
[t[0]]: [
...finalObj[t[0]],
t[1]
]
}
}else {
finalObj = {
...finalObj,
[t[0]]: [ t[1] ]
}
}
}
return s;
});
finalArr.push(finalObj);
}
console.log(finalArr);
You could do something like this:
const arr = [
{ section: "a", data: [1, 2] },
{ section: "b", data: [3, 4, 5, 6] },
{ section: "c", data: [7, 8, 9, 10, 11, 12, 13] }
];
const fillRange = (start, end) => {
return Array(end - start + 1).fill().map((item, index) => start + index);
};
let result = [];
let j = 0
let maxData = Math.max(...arr.map(x => x.data).flat(2))
for (let i = 0; i < 4; i++) {
if (j === 0) j = i + 1;
else j = j + 4;
const finalData = fillRange(j, j + 3).filter(x => x <= maxData);
let section = [];
arr.forEach(val => {
if(val.data.some(v => finalData.includes(v))) section.push(val.section);
});
let resObj = {page: i + 1, section: section, data: finalData}
result.push(resObj)
}
console.log(result)
Explanation:
With fillRange function I create arrays of consecutive numbers 4 by 4 (like [1,2,3,4][5,6,7,8]...). These values have an upper bound = max value found in all data arrays (fillRange(j, j + 3).filter(x => x <= maxData));
Find the section for which data includes these numbers;
Crete result object with all data found before and push it in result array.
Say I have an array:
arr = [25, 25, 25, 20, 15, 10, 10, 5];
and I want to count up the number of duplicates (ie. three 25s and 2 10s) and make a new array that becomes:
newArr = ['25 * 3', 20, 15, '10 * 2', 5];
How should I go about doing this? Thanks!
It can be solved using Set and filter
let arr = [25, 25, 25, 20, 15, 10, 10, 5];
const newArr = [...new Set(arr)].map((x) => {
const count = arr.filter(y => y == x).length
return count > 1 ? x + " * " + count: x;
})
console.log(newArr) // ["25 * 3", 20, 15, "10 * 2", 5]
or if you want the numeric value you can do that
let arr = [25, 25, 25, 20, 15, 10, 10, 5];
const newArr = [...new Set(arr)].map((x) => arr.filter(y => y == x).length * x)
console.log(newArr) // [75, 20, 15, 20, 5]
You can use a Array#forEach loop to iterate through each item of the array, keeping track of how many times each item has been seen before.
Demo:
let arr = [25, 25, 25, 20, 15, 10, 10, 5];
let result = [], seenBefore = [];
arr.forEach((item) => {
let seen = seenBefore.indexOf(item);
if (seen !== -1) return result[seen].count++;
result.push({ name: item, count: 1 });
seenBefore.push(item);
});
result = result.map(({ name, count }) =>
count > 1 ? `${name} * ${count}` : name
);
console.log(result);
The same technique but smaller using Array#reduce:
let arr = [25, 25, 25, 20, 15, 10, 10, 5];
let result = arr
.reduce(
(acc, item) => {
acc[1].indexOf(item) !== -1 ? acc[0][acc[1].indexOf(item)].count++ : (acc[0].push({ name: item, count: 1 }), acc[1].push(item));
return acc;
},
[[], []]
)[0]
.map(({ name, count }) => (count > 1 ? `${name} * ${count}` : name));
console.log(result);
You could use reduce and check if the current element in the iteration is equal to the previous element and then also what is the type of last element added to the accumulator.
const arr = [25, 25, 25, 20, 15, 10, 10, 5];
const result = arr.reduce((r, e, i, arr) => {
if (i && e === arr[i - 1]) {
if (typeof r[r.length - 1] === 'number') {
r[r.length - 1] = `${e} * 2`;
} else {
const [key, value] = r[r.length - 1].split(' * ')
r[r.length - 1] = `${key} * ${+value + 1}`
}
} else {
r.push(e)
}
return r;
}, [])
console.log(result)
I'm stuck again with some flattening and renaming of the following.
What I got:
test = [
{
date: '2020-03-30',
station: {
id: 0,
name: 'some description'
},
firstValues: [
{
result: 1,
type: 4,
max: 18,
min: 1,
},
{
result: 2,
type: 5,
max: 15,
min: 2,
}
],
lastValues: [
{
result: 1,
type: 3,
max: 17,
min: 1
},
{
result: 2,
type: 8,
max: 20,
min: 2
}
],
iD: 'xxx3',
count: 1
},
{
next object with same structure
}
]
What I try to achieve:
test = [
{
date: '2020-03-30',
station: 'some description',
first_E01_result: 1,
first_E01_type: 4,
first_E01_max: 18,
first_E01_min: 1,
first_E02_result: 2,
first_E02_type: 5,
first_E02_max: 15,
first_E02_min: 2,
last_E01_result: 1,
last_E01_type: 3,
last_E01_max: 17,
last_E01_min: 1,
last_E02_result: 2,
last_E02_type: 8,
last_E02_max: 20,
last_E02_min: 2,
iD: 'xxx3',
count: 1
},
{
next object with same structure
}
]
I'm quite aware that my approach isn't the right thing. I tried different things so far but couldn't get it working. I'm totally stuck again to find the right way because I do run into two main issues:
How can I make the difference between first and last values? (switch case or if and if else?)
and
How can I access the name property from the station object and assign it to the key of "station"
Here is my last approach which is still missing the right code for the mentioned problems:
convertTest(input) {
return input.map(obj => {
const obj1 = {};
const obj2 = {};
for (const prop in obj) {
if (obj.hasOwnProperty(prop) && Array.isArray(obj[prop])) {
for (let i = 0; i < obj[prop].length; i++) {
for (const [key, value] of Object.entries(obj[prop][i])) {
const name = 'first_EO' + (i + 1).toString() + '_' + key;
obj2[name] = value;
}
}
} else {
obj1[prop] = obj[prop];
}
const dataconverted = Object.assign({}, obj1, obj2);
return dataconverted;
}
});
}
You could take a recursive approach for all other nested objects except the first level with special cases.
var data = [{ date: '2020-03-30', station: { id: 0, name: 'some description' }, firstValues: [{ result: 1, type: 4, max: 18, min: 1 }, { result: 2, type: 5, max: 15, min: 2 }], lastValues: [{ result: 1, type: 3, max: 17, min: 1 }, { result: 2, type: 8, max: 20, min: 2 }], iD: 'xxx3', count: 1 }],
getPath = object => Object.entries(object).reduce((r, [k, v], i) => {
if (v && typeof v === 'object') {
r.push(...getPath(v).map(([left, right]) => [(Array.isArray(object) ? 'E' + (i + 1).toString().padStart(2, 0) : k) + '_' + left, right]));
} else {
r.push([k, v]);
}
return r;
}, []),
result = data.map(o => Object.fromEntries(Object.entries(o).reduce((r, [k, v]) => {
if (k === 'station') {
r.push([k, v.name]);
} else if (v && typeof v === 'object') {
if (k.endsWith('Values')) k = k.slice(0, -6);
r.push(...getPath(v).map(([left, right]) => [k + '_' + left, right]));
} else {
r.push([k, v]);
}
return r
}, [])));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You should use Map and Object.keys
var test = [{"date":"2020-03-30","station":{"id":0,"name":"some description"},"firstValues":[{"result":1,"type":4,"max":18,"min":1},{"result":2,"type":5,"max":15,"min":2}],"lastValues":[{"result":1,"type":3,"max":17,"min":1},{"result":2,"type":8,"max":20,"min":2}],"iD":"xxx3","count":1}]
console.log(flatten(test));
function flatten(arr) {
return arr.map(el => ModifyObject(el))
}
function ModifyObject(el) {
const obj = {};
obj.date = el.date;
obj.iD = el.iD;
obj.count = el.count;
obj.station = el.station.name;
flattenObjectByProperty(obj, el, 'firstValues')
flattenObjectByProperty(obj, el, 'lastValues')
return obj;
}
function flattenObjectByProperty(obj, el, property) {
(el[property] || []).map((child, i) => {
Object.keys(child).forEach(key => {
obj[property + '_E' + i + '_' + key] = child[key]
});
});
}
Please try this.
test = test.map((elem) => {
elem.firstValues.forEach((child, index) => {
for(let key in child){
let v = `first_E${index+1}_${key}`
elem[v] = child[key];
}
})
elem.lastValues.forEach((child, index) => {
for(let key in child){
let v = `last_E${index+1}_${key}`
elem[v] = child[key];
}
})
elem['station'] = elem.station.name;
delete elem.firstValues;
delete elem.lastValues;
return elem;
})
You can use Array.prototype.reduce to flatten as per your requirement
const test = [
{
date: '2020-03-30',
station: {
id: 0,
name: 'some description'
},
firstValues: [
{
result: 1,
type: 4,
max: 18,
min: 1,
},
{
result: 2,
type: 5,
max: 15,
min: 2,
}
],
lastValues: [
{
result: 1,
type: 3,
max: 17,
min: 1
},
{
result: 2,
type: 8,
max: 20,
min: 2
}
],
iD: 'xxx3',
count: 1
}
];
const result = test.reduce((acc, curr) => {
const { firstValues, lastValues, ...rest } = curr;
const modifiedFirstValues = firstValues.reduce((r, c, i) => {
Object.entries(c).forEach(([key, value]) => {
const modifiedKey = `first_E${i + 1}_${key}`;
r[modifiedKey] = value;
});
return r;
}, Object.create(null));
const modifiedLastValues = lastValues.reduce((r, c, i) => {
Object.entries(c).forEach(([key, value]) => {
const modifiedKey = `last_E${i + 1}_${key}`;
r[modifiedKey] = value;
});
return r;
}, Object.create(null));
const finalObj = {
...rest,
...modifiedFirstValues,
...modifiedLastValues
};
acc.push(finalObj);
return acc;
}, []);
console.log(result);
What is the cleanest way to reduce those array ?
data = {
id: [1, 1, 1, 3, 3, 4, 5, 5, 5, ...]
v: [10,10,10, 5, 10 ...]
}
For each id there is a v corresponding. What I want is sum up v for each id. In this example the result should be
data = {
id: [1, 3, 4, 5, ...]
v: [30, 15, ...]
}
I would go for the Array.prototype.reduce() ,simple and elegant solution
var ids = [1, 1, 1, 3, 3, 3, 3, 4, 5, 6, 6, 6],
v = [10, 10, 10, 5, 10, 10, 10, 404, 505, 600, 60, 6],
data = {};
data.v = [];
data.ids = ids.reduce(function(a, b, index) {
if (a.indexOf(b) < 0) a.push(b);
if (!data.v[a.indexOf(b)]) data.v[a.indexOf(b)] = 0;
data.v[a.indexOf(b)] += v[index];
return a;
}, []);
https://jsfiddle.net/2ssbngLr/
One way of doing this, given two arrays of equal length would be to map/reduce them:
const ids = [1, 1, 1, 3, 3];
const vs = [10,10,10,5,10];
const reduced = ids
.map((val, i) => ({ id: val, value: vs[i] }))
.reduce((agg, next) => {
agg[next.id] = (agg[next.id] || 0) + next.value;
return agg;
}, {});
console.log(reduced);
// Object {1: 30, 3: 15}
Working example: https://jsfiddle.net/h1o5rker/1/
I think it can be accomplished with reduce
var data = {
id: [1, 1, 1, 3, 3],
v: [10, 10, 10, 5, 10]
}
var sumsObjs = data.v.reduce(function(sum, val, index) {
var id = data.id[index];
if (sum[id] !== undefined) {
sum[id] = sum[id] + val;
} else {
sum[id] = val;
}
return sum;
}, {});
console.log(sumsObjs);
<script src="https://getfirebug.com/firebug-lite-debug.js"></script>
var data={
id: [1,1,1,10,123,4531],
v:[123,123,53,223,11,11,11]
},
_v = data.v, vinit;
document.write(data.v+'<br>');
for(var i=0;i<_v.length;i++){
vinit = _v[i];
for(var j=i+1; j<=_v.length;j++){
if(_v[j]===vinit){
delete _v[j];
}
}
};
document.write(data.v);
var data={
id: [1,1,1,10,123,4531],
v:[123,123,53,223,11,11,11,...]
},
_v = data.v, vinit;
for(var i=0;i<_v.length;i++){
vinit = _v[i];
for(var j=i+1; j<=_v.length;j++){
if(_v[j]===vinit){
delete _v[j];
}
}
}
the above code is just for the v but you can simultaneously reduce the repeating elements for id too by introducing some more variables
in the snippet you can see that there are the extra commas in the second line which shows that those elements were deleted
If the ids are always in order, a simple for loop can solve it. There is no need to get overly complicated.
data = {
id: [1, 1, 1, 3, 3, 4, 5, 5, 5],
v: [10, 10, 10, 5, 10, 1, 2, 3, 4]
};
var result = {
id: [],
v: []
};
(function() {
var ids = data.id,
vals = data.v,
lastId = ids[0],
runningTotal = vals[0];
for (var i = 1; i < ids.length; i++) {
if (lastId === ids[i]) {
runningTotal += vals[i];
}
if (lastId !== ids[i] || i + 1 === ids.length) {
result.id.push(lastId);
result.v.push(runningTotal);
lastId = ids[i];
runningTotal = vals[i];
}
}
}());
console.log(result);
Some people have posted some good solutions so far, but I haven't really seen one that does exactly what you're looking for. Here is one that takes your specific object and returns an object of the same format, but meeting your requirements and reduced.
// Your data object
data = {
id: [1, 1, 1, 3, 3],
v: [10,10,10, 5, 10]
}
// Assuming obj consists of `id` and `v`
function reduce(obj){
// We create our reduced object
var reducedObj = {
id: [],
v: []
}
// Next we create a hash map to store keys and values
var map = {};
for(var i=0; i<obj.id.length; ++i){
// If this key doesn't exist, create it and give it a value
if(typeof map[parseInt(obj.id[i])] === 'undefined'){
map[parseInt(obj.id[i])] = 0;
}
// Sum all of the values together for each key
map[parseInt(obj.id[i])] += parseInt(obj.v[i]);
}
// Now we map back our hashmap to our reduced object
for(var ele in map){
reducedObj.id.push(ele);
reducedObj.v.push(map[ele]);
}
// Return our new reduced object
return reducedObj;
}
var myReducedObject = reduce(data);
console.log(myReducedObject);
Working Fiddle
This is a solution for ordered id with Array.prototype.reduce().
var data = {
id: [1, 1, 1, 3, 3, 4, 5, 5, 5],
v: [10, 10, 10, 5, 10, 7, 8, 10, 13]
},
result = { id: [], v: [] };
data.id.reduce(function (r, a, i) {
if (r === a) {
result.v[result.v.length - 1] += data.v[i];
} else {
result.id.push(a);
result.v.push(data.v[i]);
}
return a;
}, -1);
document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');
Or a in situ version
var data = {
id: [1, 1, 1, 3, 3, 4, 5, 5, 5],
v: [10, 10, 10, 5, 10, 7, 8, 10, 13]
};
void function (d) {
var i = 1;
while (i < d.id.length) {
if (d.id[i - 1] === d.id[i]) {
d.id.splice(i, 1);
d.v[i - 1] += d.v.splice(i, 1)[0];
continue;
}
i++;
}
}(data);
document.write('<pre>' + JSON.stringify(data, 0, 4) + '</pre>');