Cannot use `substring` method on an array element in `.map` - javascript

I’m trying to edit an entire array by running a function on every item in it that checks if it has a double quote as the first character and then cuts it out. The code for that looks like this:
args = args.map(function(arg){
if(arg.substring(0, 1) === "\""){
return arg.substring(1)
}
});
When I run this code I get returned with the following error:
index.js:97
if(arg.substring(arg.length()-1, arg.length()) === "\""){
^
TypeError: Cannot read property 'substring' of undefined
The parameter of a function can usually be used in an if statement within the function, so I don’t know why it’s returning undefined here. This list does have items in it.

Looks like your args array is having elements of type other than string. So make sure that the elements of the args array are strings.
If you are trying to create an array of only those elements which start with a double quote (of course after removing that double quote), map() is a bad choice as it will add undefined to the resultant array. forEach() would be the better choice in such case.
var newArgs = [];
args.forEach(arg => {
if(arg[0] === '"'){
newArgs.push(arg.substring(1));
}
});
If you are trying to create an array where you will have all the elements in the args but some args elements with double quote removed (if it is the first character), then map() is a good choice, but it is being used in a wrong way.
args = args.map(function(arg){
if(arg.substring(0, 1) === "\""){
return arg.substring(1);
}
// what if the above `if` statement is false?
// This function is not returning anything in such case.
});
Correct usage would be:
args = args.map(arg => (arg[0] === '"') ? arg.substring(1): arg);
var args = ['test1', '"test2', 'test3', '"test4', '"test5'];
var newArgs = [];
args.forEach(arg => {
if(arg[0] === '"'){
newArgs.push(arg.substring(1));
}
});
console.log('forEach: ' + newArgs);
// returns ["test2", "test4", "test5"]
// Your code in question:
newArgs = args.map(function(arg){
if(arg.substring(0, 1) === "\""){
return arg.substring(1);
};
});
console.log('Your code: ' + newArgs);
// returns [undefined, "test2", undefined, "test4", "test5"]
// If you want to get all elements but with double quote removed (if present as first character
newArgs = args.map(arg => (arg[0] === '"') ? arg.substring(1): arg);
console.log('proper map: ' + newArgs);
// returns ["test1", "test2", "test3", "test4", "test5"]

for example if you have:
args = ["a","b",'"c"'];
args = args.map(arg=>arg.slice(0,1)=='"'?arg.slice(1,-1):arg)
its return
["a", "b", "c"]

You're using the map function on an empty array. So you just need to fill the args array with some values before attempting to call map on it.

TypeError: Cannot read property 'substring' of undefined
you are mapping an array which contains undefined element at certain index, now in this case before using any function you need make sure that arg is not undefined like :
args = args.map(function(arg){
if(arg!==undefined){
if(arg.substring(0, 1) === "\""){
return arg.substring(1)
}
}
})
this will make sure you are not using any member function on an undefined element, hope this will help!

Assuming you have an array that looks like this ['"item1"', 'item2', '"item3"', 'item4'];
let arr = ['"item1"', 'item2', '"item3"', 'item4'];
let newArr = arr.filter(element => (/^[^\"]/).test(element.trim()))
console.log(newArr); // item2, item4

Related

Trying to see if object key exists keep getting undefined

I have a data response that responds with different objects in an array.
I have tried a variety of different methods to determine if the key 'name' exists including:
const hasName = array.forEach(item => "name" in item )
const hasName = array.forEach(item => Object.keys(item).includes('name') )
const hasName = array[0].hasOwnProperty("name") ? true : null
const hasName = array => array.some(x => x.some(({ name }) => name));
// lodash 'has' method
const hasName = has(array, 'name')
Array1 returns objects like:
[
{
name: 'cool name'
}
]
Array2 returns objects like:
[
{
group: 'cool group'
}
]
All of the methods I tried have either returned undefined or nothing at all and I'm completely at a loss for why. I have scoured Stack Overflow and the internet trying to get a better direction or an answer but I haven't been able to find anything.
You're not returning anything from some of your calls on the array. forEach for example runs a callback, and always returns undefined see docs. Your code just isn't working because you're using the functions incorrectly.
The code below filters your array to get the elements with a name property, then counts them to see whether one or more exists, which results in a true or false being stored in the hasName variable.
let myArr = [
{
name: 'cool name'
}
]
const hasName =
myArr
.filter(a => a.hasOwnProperty("name")) // filter for elements in the array which have a name property
.length // get the number of filtered elements
> 0 // check whether the number of elements in array with name prop is more than 0
console.log(hasName)
If you are sure that the "response" is fully received before the check, THEN
Your latest variant of the check can be implemented as follows:
array.some(obj => (obj.name !== undefined)); // fast, but not define .name if it is "undefined"
array.some(obj => obj.hasOwnProperty("name")); // slower, but will define .name with any value
Your solutions are generally correct, but it looks like you're a little confused,
Array.forEach always returns "undefined":
array.forEach(obj => {
console.log("name" in obj); // true for 1st array
console.log("group" in obj); // true for 2nd array
}); // return "undefined"
array[0].hasOwnProperty() works fine, and can't return "undefined" at all.
console.log(
array[0].hasOwnProperty("name") ? true : null; // return ("true" for the 1st array) AND ("null" for the 2nd)
);
When you used the Lodash, maybe you forgot to point to the object index?
_.has(array[0], 'name'); // return ("true" for the 1st array) AND ("false" for the 2nd)
Try a for loop
for (var i = 0; i < array.length; i++) {
if (array[i].hasOwnProperty('name')) {
console.log(array[i].name); //do something here.
break;
}
}

Can someone explain me why we used curly braces "{}" in this code?

While I was trying to check how many times an element used in an array, I found this code. It is written by another user and I got it to work but I am trying to figure out why he used "{}" at the end. I know that .reduce() method can get initialValue but I could not understand the use of braces.
var a = ["a","b","b","c","a","b","d"];
var map = a.reduce(function(obj, b) { obj[b] = ++obj[b] || 1;
return obj;
}, {});
I thought that they might be the initialValue parameter since it covers the result, but when I tried to remove the braces the result was not the same. I also checked the MDN documents, found some similar code but could not wrap my mind around it since I am quite new in JavaScript.
When we use the braces I get :
{
a: 2,
b: 3,
c: 1,
d: 1
}
But when I remove the braces and run it I get:
a
I tried using brackets and it resulted as : [ a: 2, b: 3, c: 1, d: 1 ],
So it seems the braces enclose the values but shouldn't it work as usual without braces?
But when I remove the braces and run it, I get: a
This is the syntax:
arr.reduce(callback[, initialValue])
initialValue : Value to use as the first argument to the first call of the callback. If no initial value is supplied, the first element in the array will be used."
So, if you use reduce without the initialValue({}), the first item in the array will be used as the initialValue which is "a"
So, it becomes similar to:
var a = ["a", "b", "b", "c", "a", "b", "d"];
var map = a.slice(1).reduce(function(obj, b) {
obj[b] = ++obj[b] || 1;
return obj;
}, "a");
console.log(map)
In the first iteration,
obj[b] = ++obj[b] || 1;
becomes
"a"["b"] = ++"a"["b"] || 1
This neither throws an exception, nor does it change the obj string. obj is still "a" and it will be returned every time.
The braces {} represent a new empty object in javascript, In your case, it will be the object returned by the reduce method to the map variable, we need to initialize it first then fill it in the core of the reduce callback.
Value to use as the first argument to the first call of the callback. If no initial value is supplied, the first element in the array will be used. Calling reduce() on an empty array without an initial value is an error.
It's the initialValue take a look to reduce(), here's a sample, If you were to provide an initial value as the second argument to reduce(), the result would look like this:
let arr = [0, 1, 2, 3, 4];
arr = arr.reduce((accumulator, currentValue, currentIndex, array) => {
return accumulator + currentValue;
}, 10);
console.log(arr);
That is the accumulator object.You can say that it is the initial value so when the call back function will be executed the initial value will be a empty object.
So in the example below initially it is passing an object which have key e
var a = ["a", "b", "b", "c", "a", "b", "d"];
var map = a.reduce(function(obj, b) {
console.log(obj)
obj[b] = ++obj[b] || 1;
return obj;
}, {e:'test'});
console.log(map)
The second argument in the .reduce() method is the initialValue, which is a
Value to use as the first argument to the first call of the callback. If no initial value is supplied, the first element in the array will be used.
tl;dr
It's the initial value which .reduce() starts with. This is the first argument passed to the callback in the first call.
In your case the idea was to build a map of values from the array where keys in the map were the values from the array and values in the map were a number of occurrences of that value in the array.
A map in JS can be easily simulated by an object which in your case has been passed as a literal {} to the .reduce() method. The method fires the callback for each element in the array passing the result object as the first argument and the current element in the array as the second. But the problem is at the first call - what value should be used as the result object if there were no previous elements in the array to accumulate? That's why you need to pass some initial value to have something to start with. As the MDN states, if no initialValue is passed, the first element of the array is used - that's why you got a when removed initial value. When you passed [] you told JS to have an array literal as the initial value but in the callback, you treat it as an object which is allowed in JS since an array is also an object. The problem arises when you try to iterate over those properties or stringify them using JSON.stringify(). But it's for another story ;)
{} create new object if you don't add this then the first element in the array will be used.
You can see that when you run the code with {} you get an empty object as the initialValue and fulfills your requirement.
var a = ["a","b","b","c","a","b","d"];
var map = a.reduce(function(obj, b) {
"use strict";
if (Object.entries(obj).length === 0 && obj.constructor === Object) {
console.log("InitialValue is defined as object: ", obj);
}
obj[b] = ++obj[b] || 1;
return obj;
}, {});
console.log(map);
Whereas without {} it assigns the first value of array a to the obj that means now obj is a string and when you try to use it as an object then it throws error as in the below code.
var a = ["a","b","b","c","a","b","d"];
var map = a.reduce(function(obj, b) {
"use strict";
console.log("InitialValue not defined: ", obj);
obj[b] = ++obj[b] || 1;
return obj;
});
console.log(map);
I have just added "use strict" to show this error.

Get a specific value from a JSON object through a string

I'm trying to access to the hello value through a string (key)
I got undefined. I'm out of idea to make it works.
var key = "a.b.c.0";
var test = {"a":{"b":{"c":["hello","world"]}}};
console.log(test[key]); // undefined
console.log(test["a.b.c.0"]); // undefined
console.log(test["a.b.c[0]"]); // undefined
console.log(test["a.b.c"]); // fail
console.log(test.a.b.c); // [ 'hello', 'world' ]
console.log(test.a.b.c[0]); // hello
You can do something like this, but not sure how far it'll get you:
key.split('.').reduce(function(test, prop) {
return test[prop];
}, test);
Examples
'a.b.c.0'.split('.').reduce(function(test, prop) {...
// => "hello"
'a.b.c'.split('.').reduce(function(test, prop) {...
// => ["hello", "world"]
If you willing to use a library I highly recommend checking out lodash. For this you can use lodash's get method https://lodash.com/docs#get
_.get(test, key);
Or if you need a basic native JS implementation from Access object child properties using a dot notation string
function getDescendantProp(obj, desc) {
var arr = desc.split(".");
while(arr.length && (obj = obj[arr.shift()]));
return obj;
}
console.log(getDescendantProp(test, key));
//-> hello
another possible way ( I don't recommend it but it should work) is to use eval()
var value = eval('test' + key)

linq.js return value of (default) FirstOrDefault

Trying to check on the result of linq.js FirstOrDefault(), but checking for null or undefined isn't working. Having some trouble debugging it, but I can see that it is returning some sort of object.
There isn't any documentation for this method online that I could find.
I've tried:
var value = Enumerable.From(stuff).FirstOrDefault('x => x.Name == "Doesnt exist"')
if (value) {
alert("Should be not found, but still fires");
}
if (value != null)
alert("Should be not found, but still fires");
}
The signatures for the FirstOrDefault() function is:
// Overload:function(defaultValue)
// Overload:function(defaultValue,predicate)
The first parameter is always the default value to return if the collection is empty. The second parameter is the predicate to search for. Your use of the method is wrong, your query should be written as:
var value = Enumerable.From(stuff)
.FirstOrDefault(null, "$.Name === 'Doesnt exist'");
We figured out the answer as I was typing this out. Since there is so little documentation, I'll share.
You need to move the lambda into a Where clause before the FirstOrDefault().
When
var someArray = ["Foo", "Bar"];
var result = Enumerable.From(someArray).Where('x => x == "Doesnt exist"').FirstOrDefault();
Result is undefined (correct)
When
var someArray = ["Foo", "Bar"];
var result = Enumerable.From(someArray).Where('x => x == "Bar"').FirstOrDefault();
Result is 'Bar' (correct)
When
var someArray = ["Foo", "Bar"];
var result = Enumerable.From(someArray).FirstOrDefault('x => x == "Bar"');
Result is 'Foo' (incorrect)

Best way of basically doing a `where` clause in Javascript?

I'm trying to parse some JSON that is sent to me and it's all in the format of
[{key:value},{key2:value2}, ... ]
What would be the best way to get the value of key2 in this? Is there a way to do it without doing a for loop?
You could use the Select function from the Underscore.js library.
Not really, but it wouldn't be hard to create a function to do that. However, it would indeed involves a for loop.
For the sake of completion, that would be the function:
function selectWhere(data, propertyName) {
for (var i = 0; i < data.length; i++) {
if (data[i][propertyName] !== null) return data[i][propertyName];
}
return null;
}
Usage:
var key2value = selectWhere(data, "key2");
Javascript Array comes with methods that do just what you are asking for - find entries without you having to code a for-loop.
You provide them with the condition that you want. A compact and convenient way to do that is with an arrow (or "lambda") function. In your case, you are looking for array entries that have a specific key, so the arrow function could look something like this:
e => e.hasOwnProperty("key2")
Following the lead of some of the others, let's start with the assumption
var arr = [{key:"value"}, {key2:"value2"}, {key3:"value3"}]
If you expect that at most one member of the array has the key you want, you can use the find() function. It will test each array member until it finds one where your condition is true, and return it. If none are true, you'll get undefined.
var foundentry = arr.find(e => e.hasOwnProperty("key2"))
Either foundentry will be undefined or it will be the {key2:"value2"} that you are looking for, and can extract value2 from it.
If arr can have more than one entry with the key that you are looking for, then instead of find() use filter(). It gives back an array of entries that meet your criteria.
var foundarray = arr.filter(e => e.hasOwnProperty("key2"))
jQuery grep() is a good analog for a Where clause:
var array = [{key:1},{key:2}, {key:3}, {key:4}, {key:5}];
var filtered = jQuery.grep(array, function( item, index ) {
return ( item.key !== 4 && index > 1 );
});
Your filtered array will then contain two elements,
[{key:3}, {key:5}]
You can't do it with an array, but you can make an associative array like object with it. Once you make it, you can use it like hash.
var arr = [{key:value},{key2:value2}, ... ], obj = {};
for (var i = 0, len = arr.length; i < len; i++) {
$.extend(obj, arr[i]);
}
console.log(obj.key2); // value2
Here's an example that prototype's the Array object. Note: this is shown for example - find is not a good name for this function, and this probably will not be needed for all arrays
Instead, consider just using the function definition and creating a function like getObjVal, calling like getObjVal(arr,'propName'), similar to LaurenT's answer.
Given
var arr = [{key:'value'},{key2:'value2'}];
Definition
// for-loop example
Array.prototype.find = function (prop){
for(var i=this.length; i--; )
if (typeof this[i][prop] !== 'undefined')
return this[i][prop];
return undefined;
}
// for-each loop example
Array.prototype.find = function (prop){
for (var i in this)
if ( this.hasOwnProperty(i) && typeof this[i][prop] !== "undefined" )
return this[i][prop];
return undefined;
}
Usage
console.log( arr.find('key2') ); // 'value2'
console.log( arr.find('key3') ); // undefined
Use .filter() method for this object array, for example in your case:
var objArray = [{key:"Hello"},{key2:"Welcome"} ];
var key2Value=objArray.filter(x=>x.key2)[0].key2;
Regex - no for loop:
var key2Val = jsonString.match(/\{key2:[^\}]+(?=\})/)[0].substring("{key2:".length);
Top answer does the job. Here's a one liner version of it using lodash (same as underscore for the most part):
var result = _.filter(data, _.partialRight(_.has, 'key2'));
In lodash, select is just an alias for filter. I pass it the data array filled with objects. I use _.has as the the filter function since it does exactly what we want: check if a property exists.
_.has expects two args:
_.has(object, path)
Since _.has expects two arguments, and I know one of them is always constant (the path argument). I use the _.partialRight function to append the constant key2. _.partialRight returns a new function that expects one argument: the object to inspect. The new function checks if obj.key2 exists.
Heyas. You can use the lodash library's .reduce() or .transform() functions to implement this. Lodash is more modular than underscore (Underscore around 5kb, Lodash around 17kb), but is generally lighter because you only include the specific modules you need
(please see: https://news.ycombinator.com/item?id=9078590 for discussion). For this demonstration I will import the entire module (generally not an issue on the backend):
I wrote these snippets for either scenario which handle both numeric and non-numeric arguments.
https://lodash.com/docs#reduce
https://lodash.com/docs#transform
Pull in lodash:
var _ = require('lodash');
_.reduce() to where clause:
var delim = ' WHERE ', where = _.isEmpty(options) ? '' : _.reduce(options, function(r, v, k) {
var w = r + delim + k + '=' + (_.isNumber(v) ? v : ("'" + v + "'"));
delim = ' AND ';
return w;
}, '');
_.transform() to where clause:
var where = _.isEmpty(options) ? '' : ' WHERE ', delim = '';
_.transform(options, function(r, v, k) {
where = where + delim + k + '=' + (_.isNumber(v) ? v : ("'" + v + "'"));
delim = ' AND ';
});
Hope that helps.
Try this:
var parsedJSON = JSON.parse(stringJSON);
var value = parsedJSON['key2'];

Categories

Resources