Can you use includes() within find()? - javascript

When I try to use includes() within find() it doesn't come further than 2 items. The JSON file is valid. So I was wondering, is there a better solution since this doesn't seem to work?
async function getTheRightObject(input){
let Obj = await aJSONFile.find(item => item.AnArray.includes(input));
console.log(Obj);
return Obj;
}
let userInput = "annother one";
getTheRightObject(userInput).then(function(output){
console.log(output);
}).catch(function (err) {
//Error things
});
JSON something like:
[{
"Id": 1,
"Code": "586251af58422732b34344c340ba3",
"Input": ["official Name", "officialname", "oficial name", "officcial name"],
"Name": "Official Name",
"Flavor": "",
"Image": "https://123.com/image.png"
},
{
"Id": 2,
"Code": "597f723dceeca347a243422f9910e",
"Input": ["another one", "anotherone", "annother one", "another 1"],
"Name": "Another One",
"Flavor": "A bit of text",
"Image": "http://123.com/image2.png"
},
etc...
]
So I want to search for an object in this JSON file, which matches the users' input with the object Input of the JSON file, and sends back the Name. But this solution only seems to work for the first 2/3 items or so.
Edit:
Well, it seems I only had lower case character in the first 2 objects. In the other objects in the json file I also used upper case characters.
So my solution final is;
All object.Input = ['text1', 'text2', 'text3, 'etc'] in the json file are lower case now
use toLowerCase() on the input. Like:
let Obj = await aJSONFile.find(item => item.AnArray.includes(input.toLowerCase));
This works in my case because I know the objects are quite unique in my case. In any other cases (ie when you expect multiple objects) you can beter use the solution of Tiny Giant or varit05 down here

Here you go!
find: The find() method returns the value of the first element in the array that satisfies the provided testing function.
Documentation: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
includes: The includes() method determines whether an array includes a certain element, returning true or false as appropriate.
Documentation: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
To Answer your question:
Try to use for loop with if for desired data from an array of object.
Hope it helps!

It looks like you're looking for Array#filter, which returns a new array containing all elements that cause the provided function to return true, whereas Array#find returns the value of the first element that causes the provided function to return true.
In the example below, I've condensed the JSON, some of the variable names, and removed the irrelevant async/await usage to aid in readability for future readers.
let data = JSON.parse('[{"id":1,"arr":["a","aa","aaa"]},{"id":2,"arr":["b","bb","bbb"]},{"id":3,"arr":["c","cc","ccc"]},{"id":4,"arr":["a","bb","ccc"]}]');
const filter = (field, input) => data.filter(e => e[field].includes(input));
/*
* For demonstration purposes only.
* Map the result of the filter call to an array of
* matching id's, then output a human readable result
* Example output: "a: [1,4]"
*/
const test = (...args) => (console.log(`${args[1]}: ${JSON.stringify(filter(...args).map(e => e.id))}`), test);
test('arr', 'a')
('arr', 'aa')
('arr', 'aaa')
('arr', 'b')
('arr', 'bb')
('arr', 'bbb')
('arr', 'c')
('arr', 'cc')
('arr', 'ccc');
.as-console-wrapper { max-height: 100% ! important; height: 100% !important }

Related

How to return the key of an array of objects using its name

NOTE: I know what I'm attempting to do logically doesn't make sense in terms of why I want to achieve this, however I just want to know if it's possible and if so what I might be writing wrong?
I'm working with an array of objects like so:
this.animalsAndFruits = [
{
"category": "Apple",
"num1": 1287,
"num2": 12956
},
{
"category": "Panda",
"num1": 2574,
"num2": 25826
},
....
]
This may seem tedious and rather ridiculous however using the array I want to return the word 'category', not the value just the key 'category'.
I've tried
this.objectFromArray[0].category
However it only returns the value of the 0th indexed item (even though the 0th indexed item key will always have key 'category')
Is there another way I can accomplish this?
P.S. The reason why I want to get 'category' is because I need to set a variable = 'category', however I don't want to hardcode it directly like this
var someVar = 'category'
If it helps, the value in the key:value pair where the key = category is always a string (whereas all of the other values under different keys are numbers.
Maybe logic like so might work =>
if(value = string) then return key ?
Since the non-category properties have a consistent format (num#, right? at least going by the prior question), if you want to find the key which does not start with num, you can use Object.keys to get an array of keys, then .find the key matching the condition:
const animalsAndFruits = [
{
"category": "Apple",
"num1": 1287,
"num2": 12956
},
{
"category": "Panda",
"num1": 2574,
"num2": 25826
},
];
const propertyName = Object.keys(animalsAndFruits[0]).find(
key => !key.startsWith('num')
);
console.log(propertyName);
If you happen to be able to depend on the non-num key always being the first one defined in the objects, you could also use Object.keys(animalsAndFruits[0])[0].

Why doesn't reduce seem to fit when converting from JS to Scala

I have the following JS code...
const collection=["Thing1","Thing2"];
const doSomething = (value)=>{
switch(value){
case "Thing1":
return {
arrayItems: ["Object 1", "Object 2"]
}
break;
default:
return {
arrayItems: ["Object 3", "Object 4"]
}
}
}
const result = collection.reduce(
(result, value)=> result.concat(doSomething(value).arrayItems),
[]
);
console.log(result);
// doSomething returns { "arrayItems": ["Object 1", "Object 2"] } for Thing1
// and { "arrayItems": ["Object 3", "Object 4"] } for Thing 2
// result should be ["Object 1", "Object 2","Object 3", "Object 4"]
jsfiddle
I would now like to turn this into a similar Scala reduce like this...
val collection = ["Thing 1", "Thing 2"]
val result: Array[...] = collection
.reduce(
(array: Array[...], value: String) => {
val objectList = service.doSomething(value)
if (array != null && array.length > 0) {
array.concat(objectList)
} else {
objectList
}
});
// doSomething returns { "arrayItems": ["Object 1", "Object 2"] } for Thing1
// and { "arrayItems": ["Object 3", "Object 4"] } for Thing 2
// result should be ["Object 1", "Object 2","Object 3", "Object 4"]
But when I try this I get...
type mismatch;
found : (Array[...], String) => Array[...]
required: (java.io.Serializable, java.io.Serializable) => java.io.Serializable
val result: Array[...] = doSomething(value).reduce((array: Array[...], value: String)=>{
Is there a way to do this?
Update
I was asked for a background of what I am trying to accomplish, so the basic steps of what I am trying to accomplish are...
Take an array of strings
Run a reduce function on those strings that produces a Collection of Objects
In the reduce function we use the string to call a service which provides a collection of objects
These objects are then concatenated with the reduce value and returned
Updates per Answers
Thanks guys I didn't know about foldLeft till you brought it up and still working a bit to understand. First here is the working for loop I am trying to avoid...
var array : Array[BaseObject] = Array[BaseObject]()
collection.foreach((value: String) => {
val objectList = doSomething(value).arrayItems
array = array.concat(objectList)
});
I tried this...
val array: List[BaseObject] =
collection.foldLeft(List.empty[BaseObject]){
(myList, value) => {
val list : List[BaseObject] = List.from(doSomething(value).arrayList)
myList ++ list
}
};
But something little must be wrong because when I parse with gson toJson, I get....
{"head":{...},"next":{}}
Where head is one of the Objects but not the whole set.
The main problem is that reduce will return a value of the same type as the one contained in the collection. So, if you have an Array of Strings then the result of reduce will be a String (oh well, any supertype of String, that is why in this case that strange Serializable appears).
There is a more general version of reduce which will allow you to provide any type as output, which is foldLeft that requires an initial value.
Using that, and Lists instead of Arrays we can write this:
def concat(input: List[String])(f: String => List[String]): List[String] =
input.foldLeft(List.empty[String]) {
case (acc, str) => acc ++ f(str)
}
However, appending to a List is somewhat inefficient, so we can rewrite it like this to improve performance.
We will be prepending all results and then we will reverse the list to get the output in the expected order:
def concat(input: List[String])(f: String => List[String]): List[String] =
input.foldLeft(List.empty[String]) {
case (acc, str) => f(str) reverse_::: acc
}.reverse
However, this is a very general operation. We have a collection of some type A and a function that returns collections of some type B and we want to apply that function to all elements of the original collection and group the results into a single collection of type B.
That is the job of flatMap (which btw it is even more generic; because it works for anything that is a Monad, not only a collection).
def concat(input: List[String])(f: String => List[String]): List[String] =
input.flatMap(f)
I would recommend you to take a look to the Scaladoc as well as follow some tutorial, to learn more about all the operations the stdlib provides.
Also, please do not hesitate in asking any questions.
You can see the code running here.
Prefer Using FoldLeft as you want to accumulate Strings over a List.
I assumed that your ... are String in the following code :
val result: List[String] = myCollection.foldLeft(List.empty[String]){ (myList, value) => {
val newObject = service.doSomething(value)
myList :+ newObject
}
};
Also :
Prefer using immutable collections over mutable ones.
Usage of null is strongly discouraged in Scala. If your List is empty, that won't even be executed.
You can also use placeholders to shorten your code, which will gradually become :
val result: List[String] = myCollection.foldLeft(List.empty[String]){ (myList, value) => {
myList :+ service.doSomething(value)
}
};
then with placeholders
val result: List[String] = myCollection.foldLeft(List.empty[String]){ (_, _) => _ :+ service.doSomething(_)
};

How to check if a string contains text from an array of substrings in NodeJS and then find the index of that substring in the array?

I am able to determine the first part of the question which is to return true if a string contains text from an array of substrings in NodeJS using this:
var allowedRoles = [
"Area Director",
"Managing Director",
"Group Director"];
var currentRole = "USA Managing Director";
var lifeSaver = allowedRoles.some((substring) =>
currentRole.includes(substring)
);
console.log(lifeSaver);
Here my result is true.
But, I want to know that where in the allowedRole array my result returned true. (Expected answer: 1);
Instead of using .some you can use .findIndex
The findIndex() method returns the index of the first element in the
array that satisfies the provided testing function. Otherwise, it
returns -1, indicating that no element passed the test.
var lifeSaver = allowedRoles.findIndex((substring) =>
currentRole.includes(substring)
);

How to search a list of objects given just one word

I have an object
Const obj=[{
"name":"Teak",
"Width":"20",
"general":["it is dark","it is
brown","it is blue"],
"Characteristics":["blue","black"]
} ]
So please if the objects were much, i wanna make it possible that no matter what the person inputs, it will go through each object and return the object or objects that has that property. e.g if the person was to input blue, without anything else, how will i do it that js will go inside each obj then each characteristics and check if blue is there and then return it.
Or e.g it the person was to press dark, it has to go into general then check each sentence and if dark is there, it will return that object and other object with dark feature not minding if the other objects have general like "it is dark"
Now i am assuming this array of object will be on my js... Please help anyone.
This was what I tried doing
var allbooks =
obj.reduce(function(accumulator,
currentValue) {
return
n=currentValue.includes("black");
}, []);
console.log(allbooks)
But this is not looking in anyway correct
A naive approach would be to convert the obj to string and invoke string.include.
let obj = {
"name": "Teak",
"Width": "20",
"general": [
"it is dark",
"it is brown",
"it is blue"
],
"Characteristics": ["blue", "black"]
};
let check = (obj, word) =>
JSON.stringify(obj).includes(word);
console.log(check(obj, 'blue'));
console.log(check(obj, 'red'));
This has a few problems, e.g. cyclic objects can't be converted to strings (e.g. a = {}; a.x = a;) and this will search property keys as well (which may or may not be desired?).
A more robust solution would be to iterate all properties, check numbers and strings for matching word, and recursively iterate arrays and objects, while checking to avoid cyclic iterations (not implemented in below example).
let obj = {
"name": "Teak",
"Width": 20,
"general": [
"it is dark",
"it is brown",
"it is blue"
],
"Characteristics": ["blue", "black"]
};
let check = (obj, word) =>
Object.values(obj).some(value =>
typeof value === 'object' ?
check(value, word) :
String(value).includes(word));
console.log(check(obj, 'blue'));
console.log(check(obj, 'red'));
Try this:
var obj=[
{
"name":"Teak",
"Width":"20",
"general":["it is dark","it is brown","it is blue"],
"Characteristics":["blue","black"]
},
{
"name":"Teak",
"Width":"20",
"general":["it is dark","it is brown","it is blue"],
"Characteristics":["black"]
}
]
const input = 'blue';
const a = obj.filter(o => {
return o.Characteristics.includes(input)
})
console.log(a)

Difference between arrays of objects returning a new array

Well I need to find what does not have in one array for others, I think in an example I can explain better:
I have an array of objects as follows:
NATIVE: [{"_id": "asd12312312", "name": "item 01"}, {"_id": "1123rwerwe", "name": "item 02"}];
But I made an update with one value and added another, so it looked like this:
NEW: [{"_id": "1123rwerwe", "name": "item 02"}, {"name": "item 03"}];
This function needs to return me what was taken in another array, that is, I need this object of the result:
RESULT: [{"_id": "asd12312312", "name": "item 01"}];
Because comparing the "native array" and "new array" it would return what it has in the native and not in the new one, the purpose of this is to know if it removed some item.
Note that the new array exists an item without _id this is given because it added a new item, because who will generate_id is the database itself.
I'm using NODE JS so this function should be basically done inJAVASCRIPT
I have this function that tells me what it has in one and not in the other, it works very well, but for my return case only of what it does not have, it does not work:
const diffObjects = (object, base) => {
function changes(object, base) {
return _.transform(object, function (result, value, key) {
if (!_.isEqual(value, base[key])) {
result[key] = (_.isObject(value) && _.isObject(base[key])) ? changes(value, base[key]) : value;
}
});
}
return changes(object, base);
};
Something very important is the performance, because I have a N number of arrays to be sent to this function.
In my example you can see item without _id, in this case the item should be discarded from the logic, need to take into account only the items that have _id
Drawing I have two containers
01 [|||||||||||||]
02 [ |||||||||| |]
In this example I do not need the colored items, I need the items I had in 01 and now do not have in 02, you can see that the last point is colored, that is, it had no 01 and now it has 02, the embroidery is unlike this, what was in the 01 and was deleted in 03.
then the result would be
R [| || ]
That is, it had on 01 and now it does not have on 02
If I use the logic you are talking about it is returning me like this:
RESULT: [{"name": "item 03"}];
You can use the function filter and function some to get the objects which don't exist within the new array.
This approach uses the attribute _id as the key/unique name between both arrays
const native = [{"_id": "asd12312312", "name": "item 01"}, {"_id": "1123rwerwe", "name": "item 02"}],
newArray = [{"_id": "1123rwerwe", "name": "item 02"}, {"name": "item 03"}],
result = native.filter(o => !newArray.some(e => e['_id'] === o['_id']));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
If I understand that code snippet correctly what diffObjects tells you is which elements are in base argument that are NOT in the object argument.
So call diffObjects with the NEW array as the base and the NATIVE array as the object.
I believe you didn't see that solution yourself because you were thinking in terms of the original array, and a new array. If you change how you look at it, to, "I just have 2 arrays and want to know which elements are in one and not the other" it becomes more obvious what the solution is.

Categories