theArray is not defined - javascript

I try to avoid to use $.grep to filter what needs to be filter. In my case I want to remove array of objects which has an id of '123', but I'm getting theArray is not defined error.
function filter(array, conditionFunction) {
var validValues = [];
for (var index = 0; index < array.length; i++) {
if (conditionFunction(theArray[index])) {
validValues.push(theArray[index]);
}
}
}
var cart = [
{
"id": "123456",
"name": "banana",
"image": "56fca57eb239dc38e355c86b-1459398061689-2013-Le-Tour-de-Langkawi-Stage-5-3.jpg",
"price": 12,
"discount_price": 8,
"qty": 4
},
{
"id": "123",
"name": "Christ come",
"image": "56fcb471b239dc38e355c86c-1459401869191-klcc.jpg",
"price": 12.9,
"discount_price": 11.9,
"qty": 4
}
]
cart = filter(cart, function(e) {
return e.id !== '123';
});
console.log(cart);

This ought to fix your problem. You changed your array variable to be theArray in the middle of your for-loop. Javascript can't know that, so you'll have to be more supportive and tell JS which array you mean.
for (var index = 0; index < array.length; i++) {
if (conditionFunction(array[index])) {
validValues.push(array[index]);
}
}

Related

Repeat every element in array based on object properties

I have an array that I'm retrieving from an API. The array looks like this:
[{
"name": "Rachel",
"count": 4,
"fon": "46-104104",
"id": 2
},
{
"name": "Lindsay",
"count": 2,
"fon": "43-053201",
"id": 3
},
{
"name": "Michael",
"count": 5,
"fon": "46-231223",
"id": 4
}]
Then I loop through the array to create an array containing only the names.
function buildName(data) {
for (var i = 0; i < data.length; i++) {
nameList.push(data[i].name)
}
}
This also works so far, but I would like to create an array in which each name occurs as often as the object count says.
For example, the name Michael should appear five times in the array and Lindsay twice.
[
"Rachel",
"Rachel",
"Rachel",
"Rachel",
"Lindsay",
"Lindsay",
"Michael",
"Michael",
"Michael",
"Michael"
"Michael"
]
For each object create a new array using count, and then fill it with the name.
If you use flatMap to iterate over the array of objects. It will return a new array of nested objects but then flatten them into a non-nested structure.
const data=[{name:"Rachel",count:4,fon:"46-104104",id:2},{name:"Lindsay",count:2,fon:"43-053201",id:3},{name:"Michael",count:5,fon:"46-231223",id:4}];
const out = data.flatMap(obj => {
return new Array(obj.count).fill(obj.name)
});
console.log(out);
I've upgraded your functions but you can use the map method
function buildName(data){
for (let i = 0; i < data.length; i++){
let numToLoop = data[i].count
let name = data[i].name
for (let z = 0; z < +numToLoop; z++){
nameList.push(name)
}
}
}
Use an inner while loop inside the for loop:
const data = [{
"name": "Rachel",
"count": 4,
"fon": "46-104104",
"id": 2
},
{
"name": "Lindsay",
"count": 2,
"fon": "43-053201",
"id": 3
},
{
"name": "Michael",
"count": 5,
"fon": "46-231223",
"id": 4
}]
function buildName(data){
const result = [];
for (let i = 0; i < data.length; i += 1) {
let item = data[i];
let count = item.count;
while (count > 0) {
result.push(item.name);
count -= 1;
}
}
return result;
}
console.log(buildName(data));
Just add an inner loop with as many iterations as the "count" property in the object:
function buildName(data) {
const nameList = [];
for (var i = 0; i < data.length; i++) {
for (let j = 0; j < data[i].count; j++) {
nameList.push(data[i].name);
}
}
return nameList;
}
For fun
import { pipe } from 'fp-ts/lib/function';
import { chain, replicate } from 'fp-ts/lib/Array';
const arr = ...
const result = pipe(
arr,
chain(i => replicate(i.count, i.name))
);
You can use .flapMap() for that:
const arr = [{ "name": "Rachel", "count": 4, "fon": "46-104104", "id": 2 }, { "name": "Lindsay", "count": 2, "fon": "43-053201", "id": 3 }, { "name": "Michael", "count": 5, "fon": "46-231223", "id": 4 }];
const result = arr.flatMap(({count, name}) => Array(count).fill(name));
console.log(result);
Effectively you turn every element into an array of the the name property repeated count times which is then flattened into a single array.
It can be done via creating an array with repeated names in this way:
Array(count).fill(name)
Then you have to spread it into resulting array.
You can try this one-liner
const getNames = (data) =>
data.reduce(
(names, { name, count }) => [...names, ...Array(count).fill(name)],
[]
)
Note that a pure function is presented here, which is generally the preferred way of writing code. However, updating your example code might look like this
const getNames = (data) =>
data.reduce(
(names, { name, count }) => [...names, ...Array(count).fill(name)],
[]
)
function buildName(data) {
nameList = getNames(data)
}

Comparing information from an API call and an Array

I'm trying to compare the results of an API call to an existing array. Basically, I want to make a function that will loop through the array, then loop through the data from the API to see if there's a match.
Here's an example of the array I'm working with
let array = [ {
"name": "student1",
"id": 134},
{
"name": "student2",
"id": 135},
{
"name": "student3",
"id": 136}
]
Here's my function in JavaScript/jQuery
function getData() {
$.ajax({
url: "www.studentapi.com",
dataType: "json"
}).done(function(data) {
console.log(data)
}
}
The data I get back looks kind of like this:
[ {
"id": 134,
"score": 45},
{
"id": 138,
"score": 67},
{
"id": 139,
"score": 34}
]
I'm trying to find a way to find the matching ids in the array and in the data. So far I've tried:
for (let j =0; j < data.length; j++) {
if (array[j]["id"] === data[j].id) {
console.log("we have a match!")
}
else {
console.log("not a match!");
}
}
But this isn't working. Am I doing something incorrectly over here?
You can use find on an array to find an element that matches some conditional.
The below logic also uses arrow functions, but could be changed to use normal function(){}
let array = [
{
"name": "student1",
"id": 134
},
{
"name": "student2",
"id": 135
},
{
"name": "student3",
"id": 136
}
];
let data = [
{
"id": 134,
"score": 45
},
{
"id": 138,
"score": 67
},
{
"id": 139,
"score": 34
}
];
let studentData = array.map(student=>{
student.data = data.find(record=>record.id === student.id) || {};
return student;
});
console.log(studentData);
I would use the javascript filter function.
let matchingStudents = array.filter(student => {
return data.find(jsonData => student.id === jsonData.id);
});
There matchingStudents would hold all students present in the first array that are present in the second.
If you are wondering about the syntax, this is ES6. Next generation javascript. To write it in old javascript it'd be:
var matchingStudents = array.filter(function(student){
return data.find(function(jsonData){ return student.id === jsonData.id});
}
To specifically answer your question Am I doing something incorrectly over here?
Your search code here assumes that array and data will contain the exact same ids in the exact same order:
for (let j =0; j < data.length; j++) {
if (array[j]["id"] === data[j].id) {
Based on the sample data you provided, this isn't the case; you can't always compare array[j] to data[j] to match ids because (for example) it's possible you need to match array[4] to data[6].
One solution to this problem is to use a nested loop:
for (let i = 0; i < array.length; i++) {
for (let j = 0; j < data.length; j++) {
if (array[i].id === data[j].id) {
This way you'll compare every entry in array to every entry in data when looking for matches. (This is similar to what the solutions suggesting array.map and data.find are doing, with some smart early-out behavior.)
Another approach would be to sort both lists and step forward through them together.
let array = [
{ "id": 134, "name": "student1" },
{ "id": 139, "name": "student2" },
{ "id": 136, "name": "student3" }
];
let data = [
{ "id": 134, "score": 45 },
{ "id": 138, "score": 67 },
{ "id": 139, "score": 34 }
];
array.sort((a, b) => a.id - b.id)
data.sort((a, b) => a.id - b.id)
let data_i = 0;
for (let array_i = 0; array_i < array.length; array_i++) {
while (data[data_i].id < array[array_i].id) {
data_i++;
}
if (data_i < data.length && data[data_i].id === array[array_i].id) {
console.log(`Matched ${array[array_i].name} to score ${data[data_i].score}`);
} else {
console.log(`No match found for ${array[array_i].name}`);
}
}

How does `lookupIndex[row[lookupKey]] = row;` work?

I am reading learnjsdata.com and came across this unfamiliar JavaScript syntax. The syntax is as follows:
lookupIndex[row[lookupKey]] = row;
Anyone know what's happening here? I haven't seen syntax like this. Used in context:
Data
var articles = [{
"id": 1,
"name": "vacuum cleaner",
"weight": 9.9,
"price": 89.9,
"brand_id": 2
}, {
"id": 2,
"name": "washing machine",
"weight": 540,
"price": 230,
"brand_id": 1
}, {
"id": 3,
"name": "hair dryer",
"weight": 1.2,
"price": 24.99,
"brand_id": 2
}, {
"id": 4,
"name": "super fast laptop",
"weight": 400,
"price": 899.9,
"brand_id": 3
}];
var brands = [{
"id": 1,
"name": "SuperKitchen"
}, {
"id": 2,
"name": "HomeSweetHome"
}];
Function & Invocation
function join(lookupTable, mainTable, lookupKey, mainKey, select) {
var l = lookupTable.length,
m = mainTable.length,
lookupIndex = [],
output = [];
for (var i = 0; i < l; i++) { // loop through l items
var row = lookupTable[i];
lookupIndex[row[lookupKey]] = row; // create an index for lookup table
}
for (var j = 0; j < m; j++) { // loop through m items
var y = mainTable[j];
var x = lookupIndex[y[mainKey]]; // get corresponding row from lookupTable
output.push(select(y, x)); // select only the columns you need
}
return output;
};
var result = join(brands, articles, "id", "brand_id", function(article, brand) {
return {
id: article.id,
name: article.name,
weight: article.weight,
price: article.price,
brand: (brand !== undefined) ? brand.name : null
};
});
console.log(result);
Appreciate any answers or pointers, thanks!
Think of it as two separate function calls:
var rowLookup = row[lookupKey];
lookupIndex[rowLookup] = row;
It's the same as doing it all in the same line:
lookupIndex[row[lookupKey]] = row;

Get random X items from array in javascript

I have the following fiddle using test data, and I am looking through data using $.each
I can loop through no problem, but I want to loop through the data, and then get 3 objects from it at random.
Any tips or tricks would help:
https://jsfiddle.net/inkedraskal/pah44qv6/
$.each(testData,function(x, blah){
//console.log(blah._id);
//this gets each objects id & picture, but I want to get 3 random objects, and their corresponding data
var activeValue = blah._id,
pictureValue = blah.picture;
var markUp = '';
markUp += activeValue + pictureValue;
console.log(markUp);
});
with the question below, they need to be unique**
The function in the snippet below gets an array and a number (X) of items and returns a new array with X unique random items from the original array:
function getRandomItems(arr, items) {
var ret = [];
var indexes = [];
var arr_length = arr.length;
// If we don't have enough items to return - return the original array
if (arr_length < items) {
return arr;
}
while (ret.length < items) {
i = Math.floor(Math.random() * arr_length);
if (indexes.indexOf(i) == -1) {
indexes[indexes.length] = i;
ret[ret.length] = arr[i];
}
}
return ret;
}
arr = ['a', 'b', 'c', 'd', 'e']
console.log(getRandomItems(arr, 2))
You can also add the function to the Array.prototype if you want to use it on every Array in your code as a "native" function:
Array.prototype.getRandomItems = function(items) {
var ret = [];
var indexes = [];
var arr_length = this.length;
// If we don't have enough items to return - return the original array
if (arr_length < items) {
return this;
}
while (ret.length < items) {
i = Math.floor(Math.random() * arr_length);
if (indexes.indexOf(i) == -1) {
indexes[indexes.length] = i;
ret[ret.length] = this[i];
}
}
return ret;
}
arr1 = ['a', 'b', 'c', 'd', 'e']
arr2 = ['aaa', 'bbb', 'ccc', 'ddd', 'eee']
console.log(arr1.getRandomItems(1))
console.log(arr1.getRandomItems(2))
console.log(arr2.getRandomItems(3))
console.log(arr2.getRandomItems(4))
We can create getRandomEntry() function which will return one of the array's elements by using Math.random() function. We'll create a loop which will take random entry every time it iterates.
function getRandomEntry() {
return testData[Math.round(Math.random() * (testData.length - 1))];
}
for (var i=0; i<3; i++) {
var entry = getRandomEntry();
console.log(entry._id, entry.picture);
}
If you need an unique entry every time. You can keep random entries in separate array and check if new one is unqiue.
var randomEntries = [];
function getRandomEntry() {
return testData[Math.round(Math.random() * (testData.length - 1))];
}
function entryExists(entry) {
return randomEntries.indexOf(entry) > -1;
}
for (var i=0; i<3; i++) {
var entry;
do {
entry = getRandomEntry();
} while(entryExists(entry))
randomEntries.push(entry);
console.log(entry._id, entry.picture);
}
You could use a recursive function like the below.
Note that this implementation prevents duplicates in the results
function getRandomObjects(array,selected,needed){
/*
*#param array array The array to pull from
*#param selected array The array of results pulled so far
*#param needed int The number of results we want
*/
var length = array.length;
var num = Math.floor(Math.random() * length) + 1; // get random number in bounds of array
var exists=false; // make sure we didnt already pick this object
$.each(selected,function(i,obj){
if(obj.index==num)exists=true;
})
if(exists) getRandomObjects(array,selected,needed); // get a new one if this was a duplicate
else selected.push(array[num]);
if(selected.length!=needed) return getRandomObjects(array,selected,needed); // get another object if we need more
else return selected; // return the final result set
}
var testData = [
{
"_id": "57e5d1a90c4206b128cd8654",
"index": 0,
"guid": "1f3269fc-0822-4c5a-9c52-8055155b407e",
"isActive": true,
"balance": "$3,026.95",
"picture": "http://placehold.it/32x32"
},
{
"_id": "57e5d1a9a986ccb2f41cf7b9",
"index": 1,
"guid": "a6b726b6-6466-4e48-8697-1c6bd7b1c79e",
"isActive": true,
"balance": "$2,642.74",
"picture": "http://placehold.it/32x32"
},
{
"_id": "57e5d1a9f98f8b2f6880de32",
"index": 2,
"guid": "e7d736cc-19e0-4bcb-8d0a-4d17442d8cee",
"isActive": true,
"balance": "$3,341.64",
"picture": "http://placehold.it/32x32"
},
{
"_id": "57e5d1a9e40ded5b017e45cd",
"index": 3,
"guid": "64230ca8-05c0-4c39-a931-794172475a32",
"isActive": true,
"balance": "$2,196.13",
"picture": "http://placehold.it/32x32"
},
{
"_id": "57e5d1a90cc30be769a06d7c",
"index": 4,
"guid": "d6618b78-753a-4ad0-bc14-3687d0b99196",
"isActive": true,
"balance": "$1,611.62",
"picture": "http://placehold.it/32x32"
},
{
"_id": "57e5d1a92481a43f50607415",
"index": 5,
"guid": "35ec8186-9494-4f89-ab89-bed7f39872c3",
"isActive": true,
"balance": "$3,148.87",
"picture": "http://placehold.it/32x32"
},
{
"_id": "57e5d1a9164f17c558ba7ce1",
"index": 6,
"guid": "244970a0-1ce2-405a-8d69-c7903f9bf5eb",
"isActive": false,
"balance": "$3,758.13",
"picture": "http://placehold.it/32x32"
},
{
"_id": "57e5d1a95afde31c5cf592a8",
"index": 7,
"guid": "aa30c82d-dd2b-420c-8b30-7d66cec8d10b",
"isActive": true,
"balance": "$1,311.40",
"picture": "http://placehold.it/32x32"
}
]
var randomObjects=getRandomObjects(testData,[],3);
console.log(randomObjects);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
You can do this
var items = [1, 2, 3, 4, 5];
var newItems = [];
for(var i = 0; i < 3; i++) {
var idx = Math.floor(Math.random() * items.length);
newItems.push(items[idx]);
items.splice(idx, 1);
}
console.log(newItems);

How to get the unique object by comparing two sets of arrays using Javascript

I have the following two arrays:
var data1=[
{
"id": 1,
"url": "http://192.168.1.165:90/asset/"
},
{
"id": 2,
"url": "Assigned"
}
]
var data2=[
{
"id": 1,
"url": "http://192.168.1.165:90/asset/"
},
{
"id": 2,
"url": "Assigned"
},
{
"id": 3,
"url": "Assigned"
}
]
Result:
var unique=[{ {
"id": 3,
"url": "Assigned"
}}]
How can I get the unique object from these two arrays ?
I have tried using a for loop like this :
var unique = [];
for(var i = 0; i < data2.length; i++){
var found = false;
for(var j = 0; data1.length; j++){
if(data2[i].id == data1[j].id){
found = true;
break;
}
}
if(found == false){
unique.push(array1[i]);
}
}
But wanted to get a solution using functional javascript...
Try like this
var joined = data1.concat(data2);
var temp = [];
joined.forEach(function (x) {
var objList=joined.filter(function(y){ return y.id == x.id});
if(objList.length == 1) // if data count of current item in merged array is 1 that's means it belong to only one data source
temp.push(x);
})
console.log(temp)
JSFIDDLE
try this: first get the objects from data1 which are not in data2 and remove from data2 if it is there then concat it with data2.
<script>
var data1=[
{
"id": 1,
"url": "http://192.168.1.165:90/asset/"
},
{
"id": 2,
"url": "Assigned"
}
];
var data2=[
{
"id": 1,
"url": "http://192.168.1.165:90/asset/"
},
{
"id": 2,
"url": "Assigned"
},
{
"id": 3,
"url": "Assigned"
}
];
var arr3 = [];
for(var i in data1){
var dup = false;
for (var j in data2){
if (data2[j].id == data1[i].id && data2[j].url == data1[i].url) {
data2.splice(j,1);
}
}
if(dup) arr3.push(arr1[i])
}
arr3 = arr3.concat(data2);
console.log(arr3);
</script>
Edited for resulting the single unique object!
Assuming you have a function:
function unique(arr) {
var uni = [];
for(var i=0; i<arr.length; ++i) {
var rep = -1;
for(var j=0; j<arr.length; ++j)
if(arr[i].id == arr[j].id) rep++;
if (!rep) uni.push(arr[i]);
}
return uni;
}
this would work and give you the single unique object:
var u = unique(data1.concat(data2));
The idea is to make an union of the two given arrays and then iterate through setA and look for the matching properties and values in setA and in union. If found, then the index is stored. If there are more than one index, delete all items from union whith the indices.
The rest is then the symmetric difference.
var data1 = [{ "id": 1, "url": "http://192.168.1.165:90/asset/" }, { "id": 2, "url": "Assigned" }],
data2 = [{ "id": 1, "url": "http://192.168.1.165:90/asset/" }, { "id": 2, "url": "Assigned" }, { "id": 3, "url": "Assigned" }];
function symmetricDifference(setA, setB) {
var union = setA.concat(setB);
setA.forEach(function (a) {
var aK = Object.keys(a),
indices = [];
union.forEach(function (u, i) {
var uK = Object.keys(u);
aK.length === uK.length &&
aK.every(function (k) { return a[k] === u[k]; }) &&
indices.push(i);
});
if (indices.length > 1) {
while (indices.length) {
union.splice(indices.pop(), 1);
}
}
});
return union;
}
document.write('<pre>' + JSON.stringify(symmetricDifference(data1, data2), 0, 4) + '</pre>');

Categories