join two arrays as one - javascript

I have searched and the solution I have seen is arr1.push(...arr2), but when i try it and console log the result i only get a number returned which I guess is the length or something.
My first arr looks like this
Array [
Object {
"first_name": "ann",
"id": "23440",
"last_name": "",
"phone_number": "+51556078",
},
Object {
"first_name": "steve",
"id": "15692",
"last_name": "",
"phone_number": "+15953333",
},
Object {
"first_name": "John",
"id": "13111",
"last_name": "",
"phone_number": "+43879009",
},
]
second array
Array [
Object {
"first_name": "King",
"gender": "",
"id": 3,
"identification": "",
"last_name": "gerald",
"phone_number": "+65060738",
},
Object {
"first_name": "Jonny",
"gender": "",
"id": 4,
"identification": "",
"last_name": "Bro",
"nin": "",
"phone_number": "+51556078",
},
]
what i want is all the objects in the first array to be appended to the second array so i can display one list of first_name and phone_number

Try with the concat() function, It would return a new array result that contains array1 and array2 values:
let array1 = [1, 2, 3];
let array2 = [4, 5, 6];
let result = array1.concat(array2);
console.log(result);
More info at: https://www.w3schools.com/jsref/jsref_concat_array.asp.
As #Boaz said, you can also use the push() method, but It will change the original array. This approach would return the length of the modified array:
let array1 = [1, 2, 3];
let array2 = [4, 5, 6];
let array1_length = array1.push(...array2);
console.log(array1_length); //print new array1 length
console.log(array1); //print new array

This is because .push() returns the new length of the array. console.log(array1.push(...array2)) will return the (array1.length + arra2.length)
let a = [1,2,3]
let b = [5,6]
console.log(a.push(4))
console.log(a)
console.log(a.push(...b))
console.log(a)
You can log the array variable to check that your array is well modified.
If you want to make use of the spread operator you can always do:
let c = [...a,...b]

Related

Reduce objects to objects and arrays when Express query returns multiple objects on a many to many query

I have some SQL queries that I'm running return multiple objects when we have a many to many mapping in express, I'm trying to find a tool to reduce common objects to have nested arrays of objects.
ie.
SELECT *
FROM User
LEFT JOIN UserAddress ON UserAddress.user_id = User.user_id
LEFT JOIN Address ON Address.address_id = UserAddress.address_id;
we get a response of
[
{
"user_id": 1,
"name": "test name",
"address_id": 1,
"address": "1234 address way"
},
{
"user_id": 1,
"name": "test name",
"address_id": 2,
"address": "5678 new address"
},
{
"user_id": 2,
"name": "diff name",
"address_id": 1,
"address": "1234 address way"
}
]
and I would like to use a tool in javascript that will reduce the array of objects to look like this
[
{
"user_id": 1,
"name": "test name",
"address": [
{
"address_id": 1,
"address": "1234 address way"
},
{
"address_id": 2,
"address": "5678 new address"
}
]
},
{
"user_id": 2,
"name": "diff name",
"address_id": 1,
"address": "1234 address way"
}
]
but I'm not sure what that is called or if any tool exists that can do this?
Here's a solution that is a little generic, allowing you to specify what you're trying to collate and into what. It uses a Map object in order to help with the collation of the target key (user_id in your case):
function collate(sourceArray, keyName, collectionName, collectionFields) {
let collection = new Map();
for (let item of sourceArray) {
let targetObj = collection.get(item[keyName]);
if (!targetObj) {
targetObj = Object.assign({}, item);
// remove the properties we are collecting
for (let field of collectionFields) {
delete targetObj[field];
}
targetObj[collectionName] = [];
collection.set(item[keyName], targetObj);
}
let collectedObj = {};
// copy over the fields we are collecting
for (let field of collectionFields) {
collectedObj[field] = item[field];
}
targetObj[collectionName].push(collectedObj);
}
// now convert Map to the final array
return Array.from(collection.values());
}
Because I think it makes a lot more sense for whoever is using the resulting data, it always puts the address fields into an array, even if there is only one address and thus its an array of length 1. This will make it a lot easier for whoever is iterating this data to use it without all sorts of special conditions for reading it as the data is consistently located whether there is one or more than one address. The reader can always get the length of the array to see for themselves how many addresses there are.
And, you could use it on your data like this:
let data = [
{
"user_id": 1,
"name": "test name",
"address_id": 1,
"address": "1234 address way"
},
{
"user_id": 1,
"name": "test name",
"address_id": 2,
"address": "5678 new address"
},
{
"user_id": 2,
"name": "diff name",
"address_id": 1,
"address": "1234 address way"
}
];
function collate(sourceArray, keyName, collectionName, collectionFields) {
let collection = new Map();
for (let item of sourceArray) {
let targetObj = collection.get(item[keyName]);
if (!targetObj) {
targetObj = Object.assign({}, item);
// remove the properties we are collecting
for (let field of collectionFields) {
delete targetObj[field];
}
targetObj[collectionName] = [];
collection.set(item[keyName], targetObj);
}
let collectedObj = {};
// copy over the fields we are collecting
for (let field of collectionFields) {
collectedObj[field] = item[field];
}
targetObj[collectionName].push(collectedObj);
}
// now convert Map to the final array
return Array.from(collection.values());
}
let result = collate(data, "user_id", "address", ["address", "address_id"]);
console.log(result);
Or, if you really don't want the one element array, you can post process that out at the end:
let data = [
{
"user_id": 1,
"name": "test name",
"address_id": 1,
"address": "1234 address way"
},
{
"user_id": 1,
"name": "test name",
"address_id": 2,
"address": "5678 new address"
},
{
"user_id": 2,
"name": "diff name",
"address_id": 1,
"address": "1234 address way"
}
];
function collate(sourceArray, keyName, collectionName, collectionFields) {
let collection = new Map();
for (let item of sourceArray) {
let targetObj = collection.get(item[keyName]);
if (!targetObj) {
targetObj = Object.assign({}, item);
// remove the properties we are collecting
for (let field of collectionFields) {
delete targetObj[field];
}
targetObj[collectionName] = [];
collection.set(item[keyName], targetObj);
}
let collectedObj = {};
// copy over the fields we are collecting
for (let field of collectionFields) {
collectedObj[field] = item[field];
}
targetObj[collectionName].push(collectedObj);
}
// now convert Map to the final array
let result = Array.from(collection.values());
// remove single element arrays and copy back to main object
for (let item of result) {
let array = item[collectionName];
if (array.length === 1) {
// remove the array
delete item[collectionName];
// copy the fields from the one array element back to the main object
Object.assign(item, array[0]);
}
}
return result;
}
let result = collate(data, "user_id", "address", ["address", "address_id"]);
console.log(result);

How can I get unordered array of keys from object

I have data from backend in my js like this:
var list = {
"6": {
"id": 6,
"name": "John",
"age": 31
},
"42": {
"id": 42,
"name": "Alex",
"age": 25
},
"3": {
"id": 3,
"name": "Tim",
"age": 58
},
};
Then I need to display this data in my angular html template through ngFor directive. But first I have to get an array of object keys:
var listKeys= Object.keys(list);
Next I can output data in template:
<div *ngFor="let item of listKeys">
<p>{{list[item].id}}</p>
<p>{{list[item].name}}</p>
<p>{{list[item].age}}</p>
<hr>
</div>
But the problem is that order of my data changed. I have in listKeys next array ["3", "6", "42"]. But I want to have original order in that one ["6", "42", "3"]. One of solutions that I have found is make keys as not numeric string. For example:
var list = {
"+6": {...},
"+42": {...},
"+3": {...},
};
But I don't have access to backend. I need another solution.
P.S. The way in which I get data from the backend
getData() {
this._dataService.getList(this.name, this.age).subscribe(res => {
this.list = JSON.parse(JSON.stringify(res));
this.listKeys = Object.keys(this.list);
});
}
By definition, an object is an unordered collection of properties. As a solution, you could use an array instead of an object:
The first step would be to convert the response from the server to an array in the same order.
// Original JSON string received from API
var jsonString = `{
"6": {
"id": 6,
"name": "John",
"age": 31
},
"42": {
"id": 42,
"name": "Alex",
"age": 25
},
"3": {
"id": 3,
"name": "Tim",
"age": 58
}
}`;
// Array of ordered id's
const orderedIds = [];
// Find all id's in the JSON string and push them to the array
const pattern = /"?id"?\: (\d*)/g;
let match;
while (match = pattern.exec(jsonString)) {
orderedIds.push(parseInt(match[1]));
}
// parse the original JSON object
const originalList = JSON.parse(jsonString);
// resulting ordered Array
const result = [];
// Push the object in the array by order
for(x of orderedIds) {
result.push(originalList[x]);
}
// Log the resulting array
document.getElementById("result").innerText = JSON.stringify(result);
<pre id="result"></pre>
The result will be an array of the objects in the same order as they appeared in the JSON string:
result = [
{
"id": 6,
"name": "John",
"age": 31
},
{
"id": 42,
"name": "Alex",
"age": 25
},
{
"id": 3,
"name": "Tim",
"age": 58
},
];
After this you can use it in your template:
<div *ngFor="let item of result">
<p>{{item.id}}</p>
<p>{{item.name}}</p>
<p>{{item.age}}</p>
<hr>
</div>
this array does garantee the order of its values.
This is bound to have edge cases, but adding it because it works
If you are getting the data from the backend in the form of JSON then you can do the following
note: var json is a placeholder, as you haven't shown HOW you get your data
var json = `{
"6": {
"id": 6,
"name": "John",
"age": 31
},
"42": {
"id": 42,
"name": "Alex",
"age": 25
},
"3": {
"id": 3,
"name": "Tim",
"age": 58
}
}`;
var result = JSON.parse(json.replace(/\s?"(\d+)":/g, '"$1 ":'));
console.log(Object.keys(result));
Again, this is bound to fail, but I can't see any other way you can "fix" this on the client side - I thought JSON.parse "reviver" function would help, but it gets the properties in 3, 6, 42 order as well - so, no use at all

JSON data concatenate two data [duplicate]

This question already has an answer here:
How to concatenate two string fields into one in a JavaScript array? [closed]
(1 answer)
Closed 4 months ago.
In Javascript, How can I convert this JSON Data?
I need to concatenate the firstname and lastname into its fullname
Data
[
{
"lastname": "Stark",
"firstname": "Tony",
"id": 1
},
{
"lastname": "Parker",
"firstname": "Peter",
"id": 2
},
{
"lastname": "Rogers",
"firstname": "Steve",
"id": 3
},
]
This should be the result:
Result
[
{
"fullname": "Tony Stark",
"id": 1
},
{
"fullname": "Peter Parker",
"id": 1
},
{
"fullname": "Steve Rogers",
"id": 1
},
]
Use JSON.parse to parse your data into JavaScript object and then with Array#map function iterate over the items and populate your custom objects.
const dataAsJson = `[
{
"lastname": "Stark",
"firstname": "Tony",
"id": 1
},
{
"lastname": "Parker",
"firstname": "Peter",
"id": 2
},
{
"lastname": "Rogers",
"firstname": "Steve",
"id": 3
}
]`;
const data = JSON.parse(dataAsJson);
const changedData = data.map(item => ({ fullname: `${item.firstname} ${item.lastname}`, id: item.id }));
console.log(changedData);
If this data is available to your script as a JSON string, then you can use JSON.parse() to obtain the array of objects.
Then do whatever you want with that array of objects.
Then, eventually, convert the resulting data back to a string using JSON.stringify().
You can also use array#reduce.
const data = `[{"lastname": "Stark","firstname": "Tony","id": 1},{"lastname": "Parker","firstname": "Peter","id": 2},{"lastname": "Rogers","firstname": "Steve","id": 3}]`;
var result = JSON.parse(data).reduce((arr, obj) => {
return arr.push({fullName : obj.firstname + " " + obj.lastname, id: obj.id }), arr;
},[]);
console.log(result);
First, parse the string to get the data in JSON by using
JSON.parse()
. If you're using es6, use this:
const newArray = JSON.parse(yourArray).map((user) => ({
fullName: `${user.firstname} ${user.lastname}`,
id: user.id
}));
otherwise use this:
const newArray = yourArray.map(function (user) {
return {
fullName: user.firstname + user.lastname,
id: user.id
};
});
Thanks.
Logically all you need to do is loop through the array and make a new object with the firstname and lastname contacted. So here is a non-fancy ES5 way to do this:
// JSON Data parsed into JS Object
var arr = JSON.parse('[{"lastname":"Stark","firstname":"Tony","id":1},{"lastname":"Parker","firstname":"Peter","id":2},{"lastname":"Rogers","firstname":"Steve","id":3}]');
var newArr = [];
for(var i=0; i<arr.length; i++)
newArr.push({"fullname": arr[i]["firstname"] + " " + arr[i]["lastname"], "id": arr[i]["id"]});
console.log(JSON.stringify(newArr)); // Convert to text for JSON.

Sorting First Array With The Order Of Second Array

Suppose I am having two arrays namely namesArray and names as below
var namesArray = [{"name":"Charlie","age":3},{"name":"Dog","age":1},{"name":"Baker","age":7},{"name":"Abel","age":9}];
var names = ['Baker', 'Dog', 'Abel', 'Charlie'];
Can I achieve the following in UnderscoreJS so that sort the array named namesArray in a order so that all the name elements of namesArray will be in the same order of names .
In plain Javascript, you could use Array#sort with an object as reference for the sort order.
var namesArray = [{ "name": "Charlie", "age": 3 }, { "name": "Dog", "age": 1 }, { "name": "Baker", "age": 7 }, { "name": "Abel", "age": 9 }],
names = ['Baker', 'Dog', 'Abel', 'Charlie'],
hash = Object.create(null);
names.forEach(function (a, i) {
hash[a] = i + 1;
});
namesArray.sort(function (a, b) {
return (hash[a.name] || 0) - (hash[b.name] || 0);
});
console.log(namesArray);
Look up the index of each name in sort(). Not as performant as creating hash of indexes but chances are it's not that critical either
namesArray.sort(function(a,b){
return names.indexOf(a.name) - names.indexOf(b.name);
});
There is not lot to do with underscrore but you can do it like this:
I think using hash like what Nina does would be better than indexOf with respect to performance.
var namesArray = [{ "name": "Charlie", "age": 3 }, { "name": "Dog", "age": 1 }, { "name": "Baker", "age": 7 }, { "name": "Abel", "age": 9 }];
var names = ['Baker', 'Dog', 'Abel', 'Charlie'];
var sorted = _.sortBy(namesArray, o => names.indexOf(o.name));
console.log(sorted);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore.js"></script>

Nested linq loops

Iam trying to iterate the below JSON with linq.js , Here my scenario is I am having an array which contains 3,5,6.Based on this array values i need firstName from below JSON. How can i achieve it . The JSON is just given for an example in real time am handling with 50000 records, what is the best way to achieve this?
[
{
"id": "1",
"firstName": "John",
"lastName": "Doe"
},
{
"id": "2",
"firstName": "Anna",
"lastName": "Smith"
},
{
"id": "3",
"firstName": "Peter",
"lastName": "Jones"
},
{
"id": "4",
"firstName": "John",
"lastName": "Doe"
},
{
"id": "5",
"firstName": "Anna",
"lastName": "Smith"
},
{
"id": "6",
"firstName": "Peter",
"lastName": "Jones"
},
{
"id": "7",
"firstName": "John",
"lastName": "Doe"
},
{
"id": "8",
"firstName": "Anna",
"lastName": "Smith"
},
{
"id": "9",
"firstName": "Peter",
"lastName": "Jones"
}
]
Basically what you're trying to do is a join. A naive approach would simply just do a join.
var ids = [ 3, 5, 6 ];
var query = Enumerable.From(data)
.Join(ids, "Number($.id)", "$", "$")
.ToArray();
However this wouldn't work out well when there are many objects to work with since you're performing a linear search for the associated items. You can improve things by creating a lookup of the objects by id. You'll just have to pay the up front cost of creating the lookup.
var lookup = Enumerable.From(data)
.ToObject("Number($.id)");
var ids = [ 3, 5, 6 ];
var query = Enumerable.From(ids)
.Select(function (id) {
return lookup[id];
})
.ToArray();
If you are aware of that big amount of data would hang other process, make the user feel laggy, you can try this:
var process = function(obj, targets, callback, context) {
// Init context
var results = [];
var length = obj.length;
var procLimit = 500; // Whatever the amount you want to process at a time, higher will have higher change to cause lag on browser.
context = context ? context : null;
var current = 0;
// Loop function
var looper = function() {
if (current >= length) {
callback.call(context, result);
return;
}
var end = Math.min(length, current + procLimit);
var id, findIndex;
// Only process a fixed amount of item in a time.
for (; current < end ; ++current) {
id = parseInt(obj[current].id, 10);
findIndex = targets.indexOf(id);
// Find the matched key, and put to result.
if (findIndex >= 0) {
results.push(obj[current]);
// or you just need fname, use
// results.push(obj[current].firstName);
// remove founded from targets
targets.splice(findIndex, 1);
}
}
current += procLimit;
// Non-blocking
setTimeout(looper, 10);
};
// Non-blocking
setTimeout(looper, 10);
};
// Usage
process(YOUR_OBJ, [1, 3, 5, 6], function(processedObj){
// do somthing with the processed Object
}, THE_CONTEXT);
This function will tries to run as in background, and when it complete scan through the json array, it'll call your handler with the founded items in an array as param.
If block-effect is not in concern, then simply use the filter:
var targets = [1, 3, 5, 6];
var filterResult = YOUR_JSON.filter(function(item) {
var id = parseInt(item.id, 10);
return (targets.indexOf(id) >= 0);
}).map(function(item) { return item.firstName; });

Categories

Resources