I have this array
var array = ['20-2', '319-2', '161-2', '320-2', '12-0', '575-12', '279-12', '280-12', '412-12', '423-12', '424-12', '425-12', '291-12', '0-12', '449-12']
and I would like to remove elements that contain "-12" and "-0"
Expected Result = ['20-2', '319-2', '161-2', '320-2']
How can I achieve this expected result in javascript.
You can do this with .filter.
Example:
var array = ['20-2', '319-2', '161-2', '320-2', '12-0', '575-12', '279-12', '280-12', '412-12', '423-12', '424-12', '425-12', '291-12', '0-12', '449-12'];
var filtered = array.filter(item => !item.includes('-12') && !item.includes('-0'));
After executing this code, filtered becomes ['20-2', '319-2', '161-2', '320-2'].
You can use Array.filter method in combination with String.includes method.
Here is an example:
let array = ['20-2', '319-2', '161-2', '320-2', '12-0', '575-12', '279-12', '280-12', '412-12', '423-12', '424-12', '425-12', '291-12', '0-12', '449-12']
let newArray = array.filter((element) =>
!element.includes('-12') && !element.includes('-0')
)
console.log(newArray)
This can be achieved using the Array.filter combined with String.includes methods. The Array.filter method creates a new Array with each item that results in a positive condition.
let array = ['20-2', '319-2', '161-2', '320-2', '12-0', '575-12', '279-12', '280-12', '412-12', '423-12', '424-12', '425-12', '291-12', '0-12', '449-12']
let filteredArray = array.filter(item => (!item.includes("-12")) && !item.includes("-0"))
console.log(filteredArray)
Reference:
Array.filter
String.includes
If you want to find "12" and "0" at any position in the string (being the first or the second number) you can use a regular expression with \b symbolising a word boundary:
var array = ['20-2', '319-2', '161-2', '320-2', '12-0', '575-12', '279-12', '280-12', '412-12', '423-12', '424-12', '425-12', '291-12', '0-12', '449-12','3-120','112-14','12-7'];
const res = array.filter(el=>![/\b0\b/,/\b12\b/].some(rx=>rx.test(el)));
console.log(res)
The word boundaries in the rx ensure that elements like '3-120','112-14' will not be removed from the result set.
Instead of using two regular expressions you can - for the given problem - combine the search requirements into one:
var array = ['20-2', '319-2', '161-2', '320-2', '12-0', '575-12', '279-12', '280-12', '412-12', '423-12', '424-12', '425-12', '291-12', '0-12', '449-12','3-120','112-14','12-7'];
const res = array.filter(el=>!/\b(?:0|12)\b/.test(el));
console.log(res)
And, of course, if you only want to remove the elements when the numbers 0 and 12 appear after the (last) "-", you can do the following:
var array = ['20-2', '319-2', '161-2', '320-2', '12-0', '575-12', '279-12', '280-12', '412-12', '423-12', '424-12', '425-12', '291-12', '0-12', '449-12','3-120','112-14','12-7'];
const res = array.filter(el=>!/-(?:0|12)$/.test(el));
console.log(res)
Related
I'm creating an APA titleCase function, and I'm trying to figure out how to uppercase non-important words(the, a, an, etc). So far I've only figured out how to either uppercase or lowercase all small words, even small words that should be capitalized. I'm trying to keep small words that are not non-important words capitalized. For example, the first word of a title, and words followed by a colon and hyphen to name some. If a title object of "this title is An Example title For Javascript: volume-one," is passed into the function, I need it to return as "This Title is an Example Title for JavaScript: Volume-One." Can someone please help keep the small words lowercased.
function titleCase(title) {
title.toLowerCase();
var smallWords = ['a', 'an', 'and', 'as', 'at', 'but', 'by', 'en', 'for', 'if', 'in', 'nor', 'of', 'on', 'or', 'per', 'the', 'to'];
var titleSplit = title.split(' ');
for (var i = 0; i < titleSplit.length; i++) {
if (titleSplit[i] === titleSplit[0]) {
titleSplit[i] = titleSplit[i].charAt(0).toUpperCase() + titleSplit[i].slice(1);
} else if (titleSplit[i] === 'api' || titleSplit[i] === 'Api') {
titleSplit[i] = 'API';
} else if (titleSplit[i] === 'javascript' || titleSplit[i] === 'Javascript') {
titleSplit[i] = 'JavaScript';
} else if (smallWords.includes(titleSplit[i])) {
titleSplit[i] = titleSplit[i].toLowerCase();
}
}
title = titleSplit.join(' ');
title = title.replace(/(?:^|[\s-/])\w/g, match => {
return match.toUpperCase();
});
console.log('title:', title);
return title;
}
Here's how I do it.
const titleCase = string => {
const doNotCapitalize = ['a', 'an', 'the', 'at', 'by', 'for', 'in', 'of', 'on', 'to', 'up', 'and', 'as', 'but', 'or', 'nor'];
const words = string.split(' '); // array
const numOfWords = words.length - 1;
return string
.toLowerCase()
.split(' ')
.map((word, i) => {
// capitalize the first and last word regardless
if (i === 0 || i === numOfWords) {
return word.replace(word[0], word[0].toUpperCase());
}
return doNotCapitalize.includes(word) ? word : word.replace(word[0], word[0].toUpperCase());
})
.join(' ');
};
I'm trying to allow my user to enter a search term and then return the strings in the array that match all names they entered. So if they typed clinton here, it would find all the clintons, but if they searched hillary clinton, leaving out the rodham middle name, it would return hillary but not bill or chelsea.
const array = ['hillary rodham clinton', 'bill clinton', 'chealsea clinton', 'louise penny', 'amanda litman']
const searchTerm1 = 'hillary clinton' // should return hillary rodham clinton
const searchTerm2 = 'clinton' // should return hillary rodham clinton, bill clinton, chelsea clinton
const searchTerm3 = 'hillary' // should return hillary rodham clinton
Assuming your search terms will always be separated by a single space, you can do something like this:
const array = ['hillary rodham clinton', 'bill clinton', 'chealsea clinton', 'louise penny', 'amanda litman']
const searchTerm1 = 'hillary clinton' // should return hillary rodham clinton
const searchTerm2 = 'clinton' // should return hillary rodham clinton, bill clinton, chelsea clinton
const searchTerm3 = 'hillary' // should return hillary rodham clinton
let find = (term) => array.filter(item => term.split(' ').every(r => item.split(' ').includes(r)))
console.log(find(searchTerm1))
console.log(find(searchTerm2))
console.log(find(searchTerm3))
You can use this function to search.
function search(searchTerm, array) {
const words = searchTerm.split(" ");
let tmpArray = array;
for (let i = 0; i < words.length; i++) {
tmpArray = tmpArray.filter(obj => obj.indexOf(words[i]) >= 0);
}
return tmpArray;
}
const newArray1 = search(searchTerm1, array);
const newArray2 = search(searchTerm2, array);
const newArray3 = search(searchTerm3, array);
How to find the exact individual count of array of string in array of sentences efficiently?
Example
var names= ["jhon", "parker"];
var sentences = ["hello jhon", "hello parker and parker", "jhonny jhonny yes parker"];
Answer : jhon ->1 times (do not consider jhonny), parker-> 3 times.
what i am doing :
var lenObj ={};
for(let i=0; i< sentences.length; i++){
for(let j=0; j<name.length; j++){
// split the sentences element and compare with each word in names array. And update the count in lenObj;
}
}
Using RegEx: I am using \b for boundry.
But the problem is dynamically I am not able to assign the value: so "/\b+sentences[i]+"\b/gi" is not working
for(let i=0; i< sentences.length; i++){
for(let j=0; j<name.length; j++){
var count = (str.match("/\b+sentences[i]+"\b/gi") || []).length; // is not working
// if I hardcode it then it is working (str.match(/\bjhon\b/gi));
}
}
But i feel like above solutions are not efficient. If there any way we can do this more efficiently and optimized way?
You could split the strings and filter by name and get the length of the array.
var names = ["jhon", "parker"],
sentences = ["hello jhon", "hello parker and parker", "jhonny jhonny yes parker"],
parts = sentences.join(' ').split(/\s+/),
result = names.map(name => parts
.filter(s => s === name)
.length
);
console.log(result);
Linear time complexity:
create an object with the wanted names as key and zero as value for counting,
get sentences joined to a single sting,
split this string
iterate the parts and check if a part is a key of count, then increment count.
var names = ["jhon", "parker"],
sentences = ["hello jhon", "hello parker and parker", "jhonny jhonny yes parker"],
counts = names.reduce((o, n) => (o[n] = 0, o), {});
sentences.join(' ').split(/\s+/).forEach(s => {
if (s in counts) counts[s]++;
});
console.log(counts);
You can use the object RegExp for dynamic expressions, along with the functions map and reduce for counting.
let names= ["jhon", "parker"],
sentences = ["hello jhon", "hello parker and parker", "jhonny jhonny yes parker"],
result = names.map(n => sentences.reduce((a, s) => a + (s.match(new RegExp(`\\b${n}\\b`, "g")) || []).length, 0));
console.log(result);
Linear complexity approach
let names= ["jhon", "parker"],
sentences = ["hello jhon", "hello parker and parker", "jhonny jhonny yes parker"],
words = sentences.join(" "),
result = names.map(n => (words.match(new RegExp(`\\b${n}\\b`, "g")) || []).length);
console.log(result);
Create the regular expression by surrounding each name with \b, joining by |, then passing to new RegExp. Then you can iterate over each sentence, and each match for that pattern, and put each match on an object that counts the number of matches for each name:
var names= ["jhon", "parker"];
var sentences = ["hello jhon", "hello parker and parker", "jhonny jhonny yes parker"];
const pattern = new RegExp(names.map(name => `\\b${name}\\b`).join('|'), 'gi');
const counts = {};
for (const sentence of sentences) {
for (const match of (sentence.match(pattern) || [])) {
counts[match] = (counts[match] || 0) + 1;
}
}
console.log(counts);
I'm trying to sort an array containing strings. Each value typically has the following structure:
[registration number][ ][account number][, ][account name]
But in rare cases a value does not have the first 4 reg.numbers + a space.
This is an example of an array:
var accounts = ["1111 12345678, Account1",
"2222 12345678, Account2",
"11345678, Account3",
"12345678, Account4",
"3333 12345678, Account5"];
I can sort accounts by using accounts.sort(), and that works almost fine. BUT I would like to have the values sorted AND have the values without reg.no appear last in the sorted array (still sorted alpabetically).
So sorting the accounts array should result in this list:
1111 12345678, Account1
2222 12345678, Account2
3333 12345678, Account5
11345678, Account3
12345678, Account4
Any good suggestion to this?
You culd check for leading numbers and sort this numbers to top.
const hasLeading = s => /^\S+\s\S+\s\S+$/.test(s);
var accounts = ["1111 12345678, Account1", "2222 12345678, Account2", "11345678, Account3", "12345678, Account4", "3333 12345678, Account5"];
accounts.sort((a, b) => hasLeading(b) - hasLeading(a) || a > b || -(a < b));
console.log(accounts);
You can do it like this:
var accounts = ["1111 12345678, Account1",
"2222 12345678, Account2",
"11345678, Account3",
"12345678, Account4",
"3333 12345678, Account5"];
function compare(a, b) {
var aArr = a.split(' ');
var bArr = b.split(' ');
if (aArr.length > 2 && bArr.length > 2) {
return aArr[2] > bArr[2];
} else if (aArr.length > 2) {
return -1;
} else if (bArr.length > 2) {
return 1;
} else {
return aArr[1] > bArr[1];
}
}
console.log(accounts.sort(compare))
Get all items that contains > 2 spaces. Sort this array.
Get all items that contains === 2 spaces.
let arr = ["3333 12345678, Account5","1111 12345678, Account1",
"2222 12345678, Account2",
"11345678, Account3",
"12345678, Account4",
];
let arr1 = arr.filter((a) => {
return a.split(' ').length > 2;
});
let sortedArr = arr1.sort();
let appendArr = arr.filter((a) => {
return a.split(' ').length === 2;
});
sortedArr = [...sortedArr, ...appendArr];
console.log(sortedArr);
I have an array with values. I'm sorting it with a condition to keep certain items at the top. That is working so far. Now I want to run two conditions for example I've two prefixes to be matched with every item in the array: tableprefix and secondaryprefix. What I have already achieved is keeping tableprefix at the top. And the rest of the items must be sorted alphabetically.
What I want to achieve:
1: Array items matching tableprefix at the very top // already achieved
2: Array items matching secondaryprefix comes after tableprefix // can't figure out
3: Sort rest of the items alphabetically // already achieved
Array:
columns = [
"es_officer_name",
"es_officer_fname",
"es_officer_apply_status",
"es_officer_dob",
"es_wl_1_11_test_id",
"es_officer_id",
"es_designation_id",
"es_wl_1_11_test_edit_date",
"es_designation_title",
"es_employment_type_id",
"es_employment_type_name",
"es_service_type_id",
"es_service_type_name",
"es_wl_1_11_test_added_date",
"es_bps_id",
"es_bps_title",
"es_department_id",
"es_department_name"
];
Prefix:
var tablePrefix = "es_wl";
Sorting Algo:
columns.sort(function(a, b)
{
if (a.indexOf(tablePrefix))
{
if (b.indexOf(tablePrefix))
{
return a.localeCompare(b);
}
else
{
return 1;
}
}
else
{
if (b.indexOf(tablePrefix))
{
return -1;
}
else
{
return 0; // All prefixed are considered equal
}
}
});
Sorted Result:
[
"es_wl_1_11_test_id",
"es_wl_1_11_test_edit_date",
"es_wl_1_11_test_added_date",
"es_bps_id",
"es_bps_title",
"es_department_id",
"es_department_name",
"es_designation_id",
"es_designation_title",
"es_employment_type_id",
"es_employment_type_name",
"es_officer_apply_status",
"es_officer_dob",
"es_officer_fname",
"es_officer_id",
"es_officer_name",
"es_service_type_id",
"es_service_type_name"
]
Now what I want is to keep all the items matching the tablePrefix "es_wl" at the very top. But at the same time Add another prefix secondaryPrefix "es_officer" so that all matching items would come right after "es_wl" items and then the usual alphabetical sorting.
I have looked at several items and applied it but the items are not even moving from their place. I guess my logic is completely wrong for integrating second prefix and keeping the first one and sorting afterwards.
It is done here, run the snippet.
var columns = [
"es_officer_name",
"es_officer_fname",
"es_officer_apply_status",
"es_officer_dob",
"es_wl_1_11_test_id",
"es_officer_id",
"es_designation_id",
"es_wl_1_11_test_edit_date",
"es_designation_title",
"es_employment_type_id",
"es_employment_type_name",
"es_service_type_id",
"es_service_type_name",
"es_wl_1_11_test_added_date",
"es_bps_id",
"es_bps_title",
"es_department_id",
"es_department_name"
];
var tablePrefix = "es_wl";
var secondTablePrefix = "es_officer"
columns.sort((function(firstPattern, SecondPattern) {
this.sorting = function(a, b, tablePrefix1, primarySort) {
if (a.indexOf(tablePrefix1) != -1) {
if (b.indexOf(tablePrefix1) != -1) {
return a.localeCompare(b);
} else {
return -1;
}
} else if (b.indexOf(tablePrefix1) != -1) {
return 1;
} else {
return primarySort ? 0 : a.localeCompare(b); // All prefixed are considered equal
}
}
return function(a, b) {
var result = sorting(a, b, firstPattern, 1);
if (result == 0) {
result = sorting(a, b, SecondPattern, 0);
}
return result;
}
})(tablePrefix, secondTablePrefix));
console.log(columns)
Note: There is an issue in your sorting code - look at the sorting of es_officer it is not alphabetical, I feel even that should be required. It is all done in snippet above.
UPDATE :
To get the id column in top,
var columns = [
"es_officer_name",
"es_officer_fname",
"es_officer_apply_status",
"es_officer_dob",
"es_officer_id",
"es_designation_id",
"es_wl_1_11_test_edit_date",
"es_designation_title",
"es_employment_type_id",
"es_wl_1_11_test_id",
"es_employment_type_name",
"es_service_type_id",
"es_service_type_name",
"es_wl_1_11_test_added_date",
"es_bps_id",
"es_bps_title",
"es_department_id",
"es_department_name"
];
var tablePrefix = "es_wl";
var secondTablePrefix = "es_officer"
columns.sort((function(firstPattern, SecondPattern) {
this.sorting = function(a, b, tablePrefix1, primarySort) {
if (a.indexOf(tablePrefix1) != -1) {
if (b.indexOf(tablePrefix1) != -1) {
return a.indexOf("_id") != -1 ? -1 : b.indexOf("id") != -1 ? 1 : a.localeCompare(b);
} else {
return -1;
}
} else if (b.indexOf(tablePrefix1) != -1) {
return 1;
} else {
return primarySort ? 0 : a.localeCompare(b); // All prefixed are considered equal
}
}
return function(a, b) {
var result = sorting(a, b, firstPattern, 1);
if (result == 0) {
result = sorting(a, b, SecondPattern, 0);
}
return result == "retainIt" ? 0 : result;
}
})(tablePrefix, secondTablePrefix));
console.log(columns)
You could do it with a regular expression. Make the array into a string, search for the words with the prefixes :
var str = columns.toString(); // Array to string
var prefix = "es_wl";
var regex = new RegExp(prefix + "[\\w]+,", "g"); // Word with the prefix
var res = str.match(regex).sort(); // The array with the words that starts with the desired prefix
With multiple prefixes, you can put them in an array. Loop through the array, make multiple regexes and concat() the sorted array together. After that delete the words in the string with the desired prefixes with replace() :
str = str.replace(regex, "");
In total :
columns = [
"es_officer_name",
"es_officer_fname",
"es_officer_apply_status",
"es_officer_dob",
"es_wl_1_11_test_id",
"es_officer_id",
"es_designation_id",
"es_wl_1_11_test_edit_date",
"es_designation_title",
"es_employment_type_id",
"es_employment_type_name",
"es_service_type_id",
"es_service_type_name",
"es_wl_1_11_test_added_date",
"es_bps_id",
"es_bps_title",
"es_department_id",
"es_department_name"
];
var prefix1 = "es_wl";
var prefix2 = "es_officer";
var prefix3 = "es_department";
var prefixes1 = [prefix1, prefix2];
var prefixes2 = [prefix2, prefix1, prefix3];
function makeCustomOrder(prefixes, arr) {
var str = columns.toString();
var res = [];
prefixes.forEach((pre, i) => {
var regex = new RegExp(pre + "[\\w]+,", "g");
res = res.concat(str.match(regex).sort());
str = str.replace(regex, ""); // Delete the words with the desired prefixes
});
res = res.concat(str.split(",").sort()); // Put the sorted rest to the result
return res;
}
var res = makeCustomOrder(prefixes1, columns);
var res2 = makeCustomOrder(prefixes2, columns);
console.log(res); // Example 1
console.log(res2); // Example 2
The benefit of the compact function makeCustomOrder() is that you can use an array with prefixes as much as you want!