I try to search if a value exists as first word.
ex: "My name is James" , if I search for "nam" => true, if I search for "ja" => true, if I search for "ame" false.
The logic it works but I don't receive any items at the end.
let text = 'ame';
let option_location = [
{"text": "James"},
{"text": "Valkar"},
{"text": ""},
{"text": "James2"},
];
// This works but not as I wanted
let itemsLocation = '';
itemsLocation = option_location.filter(item => item.text.includes('ame'));
console.log('Values', itemsLocation);
// This is not working
let itemsLocation2 = '';
itemsLocation2 = option_location.filter(item =>{
item.text = item.text.toLowerCase();
let words = item.text.split(" ");
words.forEach((element,index) => {
if(element.startsWith(text)){
return true;
}else{
return false;
}
});
});
console.log('Values', itemsLocation2);
Use return words.some(...) instead of forEach. Returning in a forEach doesn't do anything for the result of the function passed to the filter.
The return in the forEach just returns from one iteration of the forEach and the true/false value is thrown away. It does not return a result immediately to the predicate of the filter.
this.itemsLocation2 = this.option_location.filter(item =>{
item.text = item.text.toLowerCase();
let words = item.text.split(" ");
words.forEach((element,index) => {
if(element.startsWith(text)){
return true; // returns from one forEach iteration, not from filter.
}else{
return false; // returns from one forEach iteration, not from filter.
}
});
});
Use a technique like this instead:
let text = 'My name is James';
let searches = ['nam', 'ja', 'ame'];
let words = text.toLowerCase().split(" ");
for(let searchTerm of searches) {
let found = words.some(w => w.startsWith(searchTerm));
console.log(`${searchTerm} => ${found}`);
}
The reason is that you used startswith() function which checks if the word starts with the given string which obviously name does not start with ame.
Whereas James starts with ja and name starts with nam
The includes() function just checks if the word contains the given string no matter where it is.
Try some thing like this. Use filter and combination with startsWith
const option_location = [
{ text: "James" },
{ text: "Valkar" },
{ text: "" },
{ text: "James2" }
];
const items = (data, text) =>
data.filter(item => text.split(" ").some(word => item.text.startsWith(word)));
console.log(items(option_location, "he ame"));
console.log(items(option_location, "ok Ja"));
You could also simplify things by using regular expressions.
The expression would be:
/\W[your key without brackets]/gmi
In JavaScript it would look like this:
/* The needles */
var needle1 = 'nam';
var needle2 = 'ja';
var needle3 = 'ame';
/* The haystack to search for */
var haystack = 'My name is James';
/* The code */
var exp1 = new RegExp('\\W' + needle1, 'gmi');
var matches1 = haystack.match(exp1);
console.log('Needle 1 found:', matches1 !== null);
var exp2 = new RegExp('\\W' + needle2, 'gmi');
var matches2 = haystack.match(exp2);
console.log('Needle 2 found:', matches2 !== null);
var exp3 = new RegExp('\\W' + needle3, 'gmi');
var matches3 = haystack.match(exp3);
console.log('Needle 3 found:', matches3 !== null);
Hope that helps :-)
Related
I'm wondering, if there is a way to filter an array or stream and apply a function A to all matches and a function B to all non-matches in JavaScript. Here is some example code that explains it a bit more:
// initial data
var names = ['Matthias', 'Maria', 'Bob', 'Anton'];
var namesWithM;
var namesWithoutM;
// gets only names starting with M, but not the others at the same time
namesWithM = names.filter(name => name.startsWith('M'))
// conditional lambda version
namesWithM = [];
namesWithoutM = [];
names.forEach(name => name.startsWith('M') ? namesWithM.push(name) : namesWithoutM.push(name));
// conditional classical version
namesWithM = [];
namesWithoutM = [];
names.forEach(function(name) {
if (name.startsWith('M'))
namesWithM.push(name)
else
namesWithoutM.push(name);
});
The very first version handles just the matches but uses filter and not forEach. Is there any way to use filter and apply a function for matches and non-matches at once? Something like this pseudo code:
names.filter(name.startsWith('M')).apply(namesWithM::push).or(namesWithoutM::push);
filter returns an array. So you can use this array to fill with name which either starts with M or not.
In the below example the filter is filling the array with name starts with M. In filter callback the name not starting with M are filled in another array
// initial data
var names = ['Matthias', 'Maria', 'Bob', 'Anton'];
var namesWithM;
var namesWithoutM = [];
namesWithM = names.filter((name) => {
if (!name.startsWith('M')) {
namesWithoutM.push(name)
}
return name.startsWith('M');
});
console.log(namesWithM, namesWithoutM);
I would use reduce to group data into 2 mentioned cases. I don't see any reason to use filter here
let names = ['Matthias', 'Maria', 'Bob', 'Anton'];
let [namesWithM, namesWithoutM] = names.reduce((acc, name) => {
if (name.startsWith('M')) {
acc[0] = [...(acc[0] || []), name]
return acc;
}
acc[1] = [...(acc[1] || []), name]
return acc;
}, [])
// simpler version
console.log(namesWithM, namesWithoutM);
let [namesWithM1, namesWithoutM1] = names.reduce((acc, name) => {
const index = Number(!name.startsWith('M'));
acc[index] = [...(acc[index] || []), name];
return acc;
}, [])
console.log(namesWithM1, namesWithoutM1);
const names = ['Matthias', 'Maria', 'Bob', 'Anton'];
function A(item){
console.log('filtered');
console.log(item);
}
function B(item){
console.log('not-ffiltered');
console.log(item);
}
const filteredNames = names.filter(name => {
const isValid = name.startsWith('M')
if(isValid)
A(name)
else
B(name)
return isValid;
})
I have a database in Firebase, which I then convert to an array, this is my code:
let timeRef = firebase.database().ref('root/grupo0/user0/0');
function snapshotToArray(snapshot) {
let returnArr = [];
snapshot.forEach(function(childSnapshot) {
let item = childSnapshot.val();
item.key = childSnapshot.key;
returnArr.push(item);
});
return returnArr;
};
const timeRefArray = timeRef.on('value', function(snapshot) {
console.log(snapshotToArray(snapshot));
});
Each element is like this: ^MED~#1550648873
How can I return each element only with numbers?
I think you want just only the number included in the item string. Then, you need a regex to get the number. In your code, replace the line returnArr.push(item); with:
var m = /\d+/.exec(item);
if (m) {
returnArr.push(m[0] * 1);
}
The *1 is to cast the number to integer.
You can use string.match() with a regex to extract the digit, then convert the result to a number with parseInt. You can then conditionaly push the item to the array if it is not NaN:
const items = ['^MED~#1550648873', '^MED~#'];
const returnArr = [];
items.forEach(item => {
const value = parseInt((item.match(/\d+/) || [''])[0]);
!isNaN(value) && returnArr.push(value);
});
console.log(returnArr);
Try This:
var arr = [ '^MED~#1550648873','Am2mm55','^MED' ] ;
var patt = new RegExp('\\d+','g') ;
var result = arr.reduce( (acc, ele) => {
if ( isTrue = ele.match(patt) ) { acc.push( isTrue.join('') ) ; }
return acc ;
}, []) ;
console.log( result ) ;
when returning each element to array you can use replace method:
str = item.replace(/\D/g,'');
returnArr.push(str);
then you can cut the non numeric part, before push it to your array.
I have an array which looks like
var arr = ["a|c", "a|e", "x|z"];
for(var x in arr){
var appsplit = x.split("|");
}
If the first value(ex: a) in the elements matches then it should combine the values
Ex: output
ace
xz
Please advice how this approach can be done.
You are testing everyone's reading comprehension with that riddle.
var pairs = {};
var arr = ["a|c", "a|e", "x|z"];
for(var x in arr)
{
var appsplit = arr[x].split("|");
if(pairs[appsplit[0]] !== "undefined")
{
pairs[appsplit[0]] = pairs[appsplit[0]] + appsplit[1];
}
else
{
pairs[appsplit[0]] = appsplit[1];
}
}
var matches = [];
for(var x in pairs)
{
matches.push(x + pairs[x]);
}
console.log(matches);
We need to map out the arr elements in this object called pairs. The first value in your split would be the key and the second value is appended (or assigned if it's the first match to the key)
You made an error of splitting x, but you are only splitting the index of the element, not the actual value of the element. arr[x] is the actual value, where x specifies the index in the array.
After we've gone through your arr, we can now merge the key with the values. Your output is contained in matches where the key in each pair is prepended to the value of the key's pair.
Some simple code that would to the trick here.
var arr = ["a|c", "a|e", "x|z", "c|b", "z|e", "c|a"];
var resultObj = {};
arr.forEach(function(element, index){
var array = element.split('|');
if(array.length!==2){
console.log("skipping, invalid input data", element);
} else {
var firstLetter = array[0];
var secondLetter = array[1];
if(resultObj[firstLetter]){
resultObj[firstLetter].push(secondLetter);
} else {
resultObj[firstLetter]=[secondLetter];
}
}
});
Object.keys(resultObj).forEach(function(key){
console.log(key + "," + resultObj[key]);
});
You can use .reduce(), Set to not accumulate duplicate values, .some() to check if previous array contains value in current array, .map(), Array.from() and .join() to convert array to string
var arr = ["a|c", "a|e", "x|z"];
var res = arr.reduce(function(a, b) {
var curr = b.split("|");
var set = new Set;
for (let prop of curr) set.add(prop);
if (!a.length) {
a.push(set)
} else {
for (prop of a) {
if (curr.some(function(el) {
return prop.has(el)
})) {
for (el of curr) {
prop.add(el)
}
} else {
for (let prop of curr) set.add(prop);
a.push(set)
}
}
}
return a
}, []).map(function(m) {
return Array.from([...m], function(el) {
return el
}).join("")
});
console.log(res);
I feel like this can be done more elegantly, but I didn't have time to streamline it. :) The below code will do what you want, though:
var aStartArray = **ARRAY_VALUE_HERE**;
var aSplitResultStrings = [];
// step through each element in the array
for (var i = 0, iSALength = aStartArray.length; i < iSALength; i++) {
// split the values for the current array element
var aSplitVal = aStartArray[i].split("|");
var bStringDoesNotExist = true;
// loop through the "result strings" array
for (var j = 0, iSRSLength = aSplitResultStrings.length; j < iSRSLength; j++) {
// if the first letter from the array element = the first letter of the current "result string" . . .
if (aSplitResultStrings[j].charAt(0) === aSplitVal[0]) {
// append the second letter of the array value to the current result string
aSplitResultStrings[j] = aSplitResultStrings[j] + aSplitVal[1];
// indicate that a match has been found and exit the "result string" loop
bStringDoesNotExist = false;
break;
}
}
// if there are no result strings that start with the first letter of the array value . . .
if (bStringDoesNotExist) {
// concatenate the two values in the current array value and add them as a new "result string"
aSplitResultStrings.push(aSplitVal[0] + aSplitVal[1]);
}
}
Using these arrays, the results are:
aStartArray = ["a|c", "a|e", "x|z"] //results in:
aSplitResultStrings = ["ace", "xz"]
aStartArray = ["a|b", "a|c", "a|d", "a|e", "x|y", "x|z"] //results in:
aSplitResultStrings = ["abcde", "xyz"]
aStartArray = ["a|b", "d|e", "d|f", "x|y", "g|h", "g|i", "m|n", "g|j", "a|c", "x|z"] //results in:
aSplitResultStrings = ["abc", "def", "xyz", "ghij", "mn"]
As I said, this could be more elegant (for example, you could probably use Map to make iterating through the "result strings" easier), but this makes the steps pretty clear and should get you going down the right path towards a final solution.
I have an array with X number of items. Each has variables separated by a pipe character. In a loop I can split on the pipe to get the second item; but how do I splice to remove the duplicate.
"Sometext|22621086|address|333629dc87894a7ea7df5291fa6d1836|PC_E|1803"
"Sometext2|22622138|working|d3e70175ffe942568cd21f1cf96f4d63|PC_E|1803"
"Sometext3|22622138|working|851946e6325445da99c113951590f714|PC_E|1803"
Results should be this.
"Sometext|22621086|address|333629dc87894a7ea7df5291fa6d1836|PC_E|1803"
"Sometext2|22622138|working|d3e70175ffe942568cd21f1cf96f4d63|PC_E|1803"
Note that the duplicate 22622138 is a random number so the solution needs to work for any number in this location (it's always in the arr[1] position).
This is what I tried:
$.each(arr_transcript, function (i, e) {
if (e.length != 0) {
var arr = e.split("|")
var i = arr_transcript.indexOf(arr[1]);
if (i != -1) {
arr_transcript.splice(i, 1);
}
}
});
Here's a generic function:
function uniqBy(a, key) {
let seen = new Set();
return a.filter(item => {
let k = key(item);
return !seen.has(k) && seen.add(k);
});
};
var data = [
"Sometext|22621086|address|333629dc87894a7ea7df5291fa6d1836|PC_E|1803",
"Sometext2|22622138|working|d3e70175ffe942568cd21f1cf96f4d63|PC_E|1803",
"Sometext3|22622138|working|851946e6325445da99c113951590f714|PC_E|1803"
];
var result = uniqBy(data, item => item.split('|')[1]);
console.log(result)
See here for more info.
Create a map of the numbers you want to check against, and then filter based on that
var arr_transcript = [
"Sometext|22621086|address|333629dc87894a7ea7df5291fa6d1836|PC_E|1803",
"Sometext2|22622138|working|d3e70175ffe942568cd21f1cf96f4d63|PC_E|1803",
"Sometext3|22622138|working|851946e6325445da99c113951590f714|PC_E|1803"
];
var map = arr_transcript.map(function(text) {
return text.split('|')[1];
});
var filtered = arr_transcript.filter(function(item, index) {
return index === map.lastIndexOf( map[index] );
});
console.log(filtered)
I am running into an issue, I have a similar array of Strings in JS:
var myArray = ["bedroomone", "bedroomonetwo", "bathroom"];
And I would like to retrieve all the elements in the array that contains the keyword 'bedroom'. How can I achieve such result ?
I tried in different ways without getting the desired result. How should I proceed ?
String.prototype.indexOf:
var PATTERN = 'bedroom',
filtered = myArray.filter(function (str) { return str.indexOf(PATTERN) === -1; });
Regexp:
var PATTERN = /bedroom/,
filtered = myArray.filter(function (str) { return PATTERN.test(str); });
String.prototype.includes (only in moderm browsers):
var PATTERN = 'bedroom',
filtered = myArray.filter(function (str) { return str.includes(PATTERN); });
var bedrooms = myArray.filter(name => name.includes('bedroom'))
Using JavaScript arrow function is much simpler
const words = ['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present'];
const result = words.filter(word => word.length > 6);
console.log(result);
// expected output: Array ["exuberant", "destruction", "present"]
// search using keyword from array
var keywordToSearch = 'Arslan'; // word to search
var keyword = keywordToSearch.toLowerCase();
var names = [{id: 1, name: 'Aqib'}, {id: 2, name: 'Arslan'}];
//search keyword from names array by name
var searchResult = names.filter(word => word.name.toLowerCase().indexOf(keyword) > -1);
console.log(searchResult);
// expected output: > Array [Object { id: 2, name: "Arslan" }]
Using javascript arrow function
Improved Microfed's answer to this
var textToSearch = 'bedroom';
var filteredArray = myArray.filter((str)=>{
return str.toLowerCase().indexOf(textToSearch.toLowerCase()) >= 0;
});
You could also use the search() method
Finds the first substring match in a regular expression search.
(method) String.search(regexp: string | RegExp): number (+1 overload)
const filterList = (data, query) => {
return data.filter(name => name.toLowerCase().search(query.toLowerCase()) !== -1);
};
const House = ["bedroomone", "bedroomtwo", "bathroom"]
const filterItems = (arr, query) => {
return arr.filter(element =>
element.toLowerCase().indexOf(query.toLowerCase()) !== -1)
}
console.log(filterItems(House, "bedroom"));