Create one array from 2 Arrays with keys x & y - javascript

I have 2 Arrays xDates and yMentions
xDates
[1453766400000, 1453852800000, 1453939200000...
yMentions
[5160, 5240, 7090...
Goal is an Array like so:
[
{
x: 1453766400000,
y: 5160
},
...
]
Trying to use Ramda Zip thought zipObj would be what I need, but the following produces just 1 object:
R.zipObj(['x', 'x', 'x'], [1, 2, 3]); => {"x": 3}
Figured perhaps I run R.zipObj on the x then the y arrays, then zip them together then set that as the Array for mentionsPointsArray below:
const createMentionPoints = (frequencyPoints, termsData) => {
const yMentions = termsData.mentions;
const propX = R.prop('x');
const xPointsFromFrequency = R.map(propX, frequencyPoints);
console.log('xDates', xPointsFromFrequency)
console.log('yMentions', yMentions)
const mentionsPointsArray = []
return frequencyPoints;
};

You should use Array#map function.
The map() method creates a new array with the results of calling a provided function on every element in this array.The provided function is a callback.
The elements from the result array are objects, like this: {"x":item, "y":yMentions[i]}.
var xDates=[1453766400000, 1453852800000, 1453939200000];
var yMentions=[5160, 5240, 7090];
console.log(xDates.map(function(elem,i){
return {"x":elem,"y":yMentions[i]}
}));

The ramda solution http://ramdajs.com/docs/#zipWith
var createPoints = (x, y) => {
return { x: x, y: y }
};
R.zipWith(createPoints, [1, 2, 3], ['a', 'b', 'c']);
// returns: [{"x": 1, "y": "a"}, {"x": 2, "y": "b"}, {"x": 3, "y": "c"}]

I think the cleanest point-free version would be:
const data1 = ['a', 'b', 'c']
const data2 = [1, 2, 3]
R.zipWith(R.objOf, data1, data2)
Please have a look at a working REPL here

Related

Converting Array of Pairs into 2 Separate Arrays Without Iteration

I have an array of pairs that looks like this [[x,y], [x,y] ... ]. I want to format it into an Object where the values are arrays of x and y values like so {keys: [x1, x2, x3 ...], values: [y1, y2, y3 ... ]}.
Are there any array/object operations to complete this operation without iterating through the original list?
The easiest and safest way is to reduce the array to an object, although it requires a loop:
const input = [[3, 300], [2, 200], [1, 100]];
const result = input.reduce((acc, [key, val]) => {
acc.keys.push(key);
acc.values.push(val);
return acc;
}, { keys: [], values: [] });
console.log(result);
I wouldn't actually use the convert to object / Map method (under Original Answer), because it has a serious caveat - duplicate entries the has the same keys would be overridden.
For example:
const input = [[3, 300], [3, 200], [3, 100]];
const obj = Object.fromEntries(input);
const result = { keys: Object.keys(obj), values: Object.values(obj) };
console.log(result);
Original Answer
Building on top of pilchard's answer, I would convert the array to a Map, and then take the Map's keys, and values. I would use a Map, and not an object, because object's keys are always strings, and if the values are integers, the object would also be sorted by their value. A Map would preserve the original type, and won't reorder them.
const input = [[3, 300], [4, 200], [1, 100]];
const map = new Map(input);
const result = { keys: [...map.keys()], values: [...map.values()] };
console.log(result);
An example of converting the same structure to an object:
const input = [[3, 300], [4, 200], [1, 100]];
const obj = Object.fromEntries(input);
const result = { keys: Object.keys(obj), values: Object.values(obj) };
console.log(result);
The process is iterative, but you can hide it by using existing Object methods: Object.fromEntries(), Object.keys(), Object.values()
const input = [['a', 1], ['b', 2], ['c', 3]];
const obj = Object.fromEntries(input);
const result = { keys: Object.keys(obj), values: Object.values(obj) };
console.log(result);
Ori Drori's refinement using a Map is more robust not only for numeric values but for any type.
const input = [[new Date(), { y: 1 }], [new Date(), { y: 2 }], [new Date(), { y: 3 }]];
const map = new Map(input);
const result = { keys: [...map.keys()], values: [...map.values()] };
console.log(result);
console.log(result.keys[0].valueOf());
No space left for losers, but just another way
const input = [[3, 300], [4, 200], [1, 100]];
const result = { keys: Array.from(input, x => x[0]), values: Array.from(input, x => x[1]) };
console.log(result);

How to insert a object in an array (as a element )

I am from C++ background.
I am trying to translate a C++ code to JavaScript.
in C++ we have vector < pair < int,int > > to store pairs.
in JS i have a situation. i want to store 2D coordinates. i actually want to push new coordinates to the array.
i did like
first I created a Object
const coordinate = {
x= 9,
y= 10
}
Then i tried to push that object into the array CoordinateStorage that i want this object to get stored
CoordinatesStorage.unshift({X : coordinate.x, Y : coordinates.y});
I know this code shown above is absolutely wrong to store an object into the array. I searched out for sources but i got nothing useful.
Please recommend some sources that i can refer for such translation related problems if possible.
Generally speaking, we should use the .push method for an array.
There are other methods available you can find them here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array but the .push method for your case is more suitable.
Basically, as a result, we want to have something like this:
[ {x: 2, y: 4 }, { x: 2, y: 4 } ] We have an array of objects.
Or we could also have an array of arrays:
[[1, 2], [3, 4], [4, 6]] Not sure if it okay for your case, but maybe as an option.
Also, we could create a class Vector and we might have something like
[ Vector { x: 1, y: 2 }, Vector { x: 3, y: 4 }, Vector { x: 4, y: 6 } ]
Let's take a look at the examples:
Using the plain object for the vector:
const coordinate1 = {
x: 2,
y: 4
};
const coordinate2 = {
x: 3,
y: 4
};
const coordinatesStorage = [];
coordinatesStorage.push(coordinate1);
coordinatesStorage.push(coordinate2);
If you will do console.log(coordinatesStorage) you will see [ { x: 2, y: 4 }, { x: 3, y: 4 } ]
Using the array to store a vector:
const coordinate1 = [1, 2];
const coordinate2 = [3, 4];
const coordinatesStorage = [];
coordinatesStorage.push(coordinate1);
coordinatesStorage.push(coordinate2);
The coordinatesStorage will be [ [ 1, 2 ], [ 3, 4 ] ]
Using the Vector class:
Maybe in your case, it would be more helpful to operate with a class Vector:
class Vector {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
const coordinatesStorage = [];
coordinatesStorage.push(new Vector(1, 2));
coordinatesStorage.push(new Vector(3, 4));
coordinatesStorage.push(new Vector(4, 6));
And here in the console you will see [ Vector { x: 1, y: 2 }, Vector { x: 3, y: 4}, Vector { x: 4, y: 6 } ]
Take a look at the Vector implementations in JS:
https://gist.github.com/jjgrainger/808640fcb5764cf92c3cad960682c677
https://github.com/maxkueng/victor/blob/master/index.js
I hope this helps. Good luck!
First initialize the array
var CoordinatesStorage = [];
//create object
const coordinate = {
x: 9, // Note - the operator is colon : not = as in the question
y: 10
}
// push to array
CoordinatesStorage.push(coordinate);
Now your array will be like this [{x:9, y:10}] if you push again the array will be [{x:9, y:10}, {x:9, y:10}]
Tip: Arrays are denoted by square brackets eg: ['math', 'science', 'english']
Objects are denoted by key-value pairs wrapped in curly brackets
eg: var student = {
name: "John", // string value
age: 6, // integer value
sex: "M",
phone: [123456789 , 564654654] // value is of array of 2 items
}

How to create a list of objects in JavaScript

I have an array of pairs of values somewhat like this:
let myarr = [[1, 'a'],
[2, 'b'],
[3, 'c']]
and one like this:
let otherArr = [5,6,7]
and I would like to convert them to an object which would be of the form:
{
"data":[
{
"id":5,
"pair":[
1,
"a"
]
},
{
"id":6,
"pair":[
2,
"b"
]
},
{
"id":7,
"pair":[
3,
"c"
]
}
]
}
As a first attempt
I tried to use a for loop and tried to create a list of the pair keys like this
for (let pair = 0; pair < myarr.length; pair++) {
myobj[pair].pair = myarr[pair]
and I get an error stating TypeError: Cannot set property 'pair' of undefined
Is there a efficient way to create a object like the example above
Thanks in advance
The reason your for loop fails is because you need to instantiate an object before you can set properties on it. For example, you could use Array.push to iterate over your array and create new objects at each index.
const myobj = { data: [] };
for (let index = 0; index < myarr.length; index++) {
myobj.data.push({ pair: myarr[index], id: otherArr[index]})
}
A shorter way to write the above, assuming that myarra and otherArr will always have the same length, would be to use Array.map to iterate over your first array and return a new one of the same length.
const myobj = {
data: myArra.map((pair, index) => ({ pair, id: otherArr[index] })
}
Try this :
let otherArr = [5,6,7];
let myarr = [[1, 'a'], [2, 'b'], [3, 'c']];
let obj = { "data":[] };
otherArr.map((item, index) => {
obj.data.push({
"id": item,
"pair": myarr[index]
})
});
console.log(obj);
You can do something like below
let myarr = [[1, 'a'],
[2, 'b'],
[3, 'c']];
let otherArr = [5,6,7];
let data = myarr.map((i,idx) => {
return {
"id": otherArr[idx],
"pair": i
};
});
console.log({data});

Promise.all on array of objects with promises with FP

So, I'm using NodeJS and Ramda and I have an Array of objects like:
[
{
x: 'abc',
y: []
},
{
x: '123',
y: [1, 2, 3]
}
]
Then I want do use x in a request which returns a promise, resulting in this (using over and lensProp from Ramda):
[
{
x: Promise<String>,
y: []
},
{
x: Promise<String>,
y: [1, 2, 3]
}
]
Now I want to turn that last array into this:
Promise<[
{
x: String,
y: []
},
{
x: String,
y: [1, 2, 3]
}
]>
How can I achieve that in a functional way (as in functional programming, not as in something that just works =])?
The best I could think of was to get all the promises from x, use Promise.all and use then to zip the result back with the ys. But I'm not accepting that as a solution.
One option is to introduce a new helper function which behaves similar to R.traverse that is specialised to Promises and will work over a specific property of an object. Let's call this traversePropP:
// traversePropP :: (a -> Promise b) -> String -> {a|...} -> Promise {b|...}
const traversePropP = R.curry((toPromiseFn, prop, obj) =>
toPromiseFn(obj[prop]).then(v => R.assoc(prop, v, obj)))
This effectively lets you produce a Promise from the specified property of an object, replacing the property with the eventual value resolved by the created Promise.
You can then use this new function to map over all the objects in your array, then pass the resulting array of Promises to Promise.all.
const traversePropP = R.curry((toPromiseFn, prop, obj) =>
toPromiseFn(obj[prop]).then(v => R.assoc(prop, v, obj)))
// example Promise-producing function that delays a value
const delayP = n => x =>
new Promise((res, rej) => setTimeout(() => res(x), n))
const fn = R.pipe(
R.map(traversePropP(delayP(500), 'x')),
x => Promise.all(x)
)
const data = [
{
x: 'abc',
y: []
},
{
x: '123',
y: [1, 2, 3]
}
]
console.log('begin')
fn(data).then(x => console.log('result:', x))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>
Here is a clean way to do what you want.
import { pipe, assign, map, get } from 'rubico'
const makeRequest = async x => {/* ... */}
const data = [
{ x: 'abc', y: [] },
{ x: '123', y: [1, 2, 3] },
]
map(assign({
x: pipe([get('x'), makeRequest]),
}))(data)
final output is a promise of an array of objects with x properties overwritten with the result of the requests

How can I turn an array into an object with the name being the first value in the array and the properties an array of the subarrays?

What is the best way to take a multidimensional array with an unknown list of elements and group it into an object to remove repeated values in the first element of the subarray:
For example, I'd like to turn this:
const arr = [[a, 1, 4], [b, 3, 4], [c, 1, 7], [a, 2, 5], [c, 3, 5]]
Into this:
arrResult = {a:[[1, 4],[2, 5]], b:[[3, 4]], c:[[1, 7],[3, 5]]}
I thought about sorting this and then splitting it or running some kind of reduce operation but couldn't figure out exactly how to accomplish it.
You only need to use reduce (and slice), no need for sorting or splitting
var arr = [['a', 1, 4], ['b', 3, 4], ['c', 1, 7], ['a', 2, 5], ['c', 3, 5]];
var arrResult = arr.reduce((result, item) => {
var obj = result[item[0]] = result[item[0]] || [];
obj.push(item.slice(1));
return result;
}, {});
console.log(JSON.stringify(arrResult));
You can use reduce like this:
const arr = [["a", 1, 4], ["b", 3, 4], ["c", 1, 7], ["a", 2, 5], ["c", 3, 5]];
var result = arr.reduce((obj, sub) => {
var key = sub[0]; // key is the first item of the sub-array
if(obj[key]) obj[key].push(sub.slice(1)); // if the there is already an array for that key then push this sub-array (sliced from the index 1) to it
else obj[key] = [sub.slice(1)]; // otherwise create a new array that initially contain the sliced sub-array
return obj;
}, {});
console.log(result);
you could use reduce and destructuring like this:
const arr = [['a', 1, 4],['b', 3, 4],['c', 1, 7],['a', 2, 5],['c', 3, 5]]
function sub(arr) {
return arr.reduce((obj, [key, ...value]) => {
obj[key] ? obj[key].push(value) : obj[key] = [value]
return obj
}, {})
}
console.log(sub(arr));
I like this solution better because it abstracts away the collation but allows you to control how items are collated using a higher-order function.
Notice how we don't talk about the kind or structure of data at all in the collateBy function – this keeps our function generic and allows for it to work on data of any shape.
// generic collation procedure
const collateBy = f => g => xs => {
return xs.reduce((m,x) => {
let v = f(x)
return m.set(v, g(m.get(v), x))
}, new Map())
}
// generic head/tail functions
const head = ([x,...xs]) => x
const tail = ([x,...xs]) => xs
// collate by first element in an array
const collateByFirst = collateBy (head)
// your custom function, using the collateByFirst collator
// this works much like Array.prototype.reduce
// the first argument is your accumulator, the second argument is your array value
// note the acc=[] seed value used for the initial empty collation
const foo = collateByFirst ((acc=[], xs) => [...acc, tail(xs)])
const arr = [['a', 1, 4], ['b', 3, 4], ['c', 1, 7], ['a', 2, 5], ['c', 3, 5]]
let collation = foo(arr);
console.log(collation.get('a')) // [ [1,4], [2,5] ]
console.log(collation.get('b')) // [ [3,4] ]
console.log(collation.get('c')) // [ [1,7], [3,5] ]
Of course you could write it all in one line if you didn't want to give names to the intermediate functions
let collation = collateBy (head) ((acc=[], xs) => [...acc, tail(xs)]) (arr)
console.log(collation.get('a')) // [ [1,4], [2,5] ]
Lastly, if you want the object, simply convert the Map type to an Object
let obj = Array.from(collation).reduce((acc, [k,v]) =>
Object.assign(acc, { [k]: v }), {})
console.log(obj)
// { a: [ [1,4], [2,5] ],
// b: [ [3,4] ],
// c: [ [1,7], [3,5] ] }
Higher order functions demonstrate how powerful generic procedures likes collateBy can be. Here's another example using the exact same collateBy procedure but performing a very different collation
const collateBy = f => g => xs => {
return xs.reduce((m,x) => {
let v = f(x)
return m.set(v, g(m.get(v), x))
}, new Map())
}
const collateEvenOdd = collateBy (x => x % 2 === 0 ? 'even' : 'odd')
const sumEvenOdd = collateEvenOdd ((a=0, b) => a + b)
let data = [2,3,4,5,6,7]
let collation = sumEvenOdd (data)
let even = collation.get('even')
let odd = collation.get('odd')
console.log('even sum', even) // 2 + 4 + 6 === 12
console.log('odd sum', odd) // 3 + 5 + 7 === 15

Categories

Resources