JS string list: transform to partial concatenation [duplicate] - javascript

I'm having trouble wrapping my head around this, but let's say there an array with these elements:
["apple", "banana", "pear", "kiwi", "orange"]
I would like to transfer this array into:
["apple", "apple/banana", "apple/banana/pear", "apple/banana/pear/kiwi", "apple/banana/pear/kiwi/orange"]
I need this in JavaScript and I'm not sure how to achieve it.
Please note that I'm currently working with ES5.

Here's a simple implementation of what you're trying to do :
ES5
var input = ["apple", "banana", "pear", "kiwi", "orange"];
var prev = '';
var output = input.map(function (el) {
el = prev + el; prev = el + '/'; return el;
});
console.log(output);
ES6
let input = ["apple", "banana", "pear", "kiwi", "orange"];
let prev= '';
let output = input.map( el => { el = prev + el; prev = el+'/'; return el})
console.log(output)

Array.map() is meant for these problems.
The map() method creates a new array with the results of calling a provided function on every element in the calling array.
And while walking through the array with map you can use join() and slice() to concatenate certain values from an original array.
let input = ["apple", "banana", "pear", "kiwi", "orange"];
let output = input.map((el, index) => {
return (input[index-1]) ? input.slice(0, index+1).join('/') : el;
})
output:
Array [
"apple",
"apple/banana",
"apple/banana/pear",
"apple/banana/pear/kiwi",
"apple/banana/pear/kiwi/orange"
]
Some more explanation on what is happening in those 3 lines:
// let's write it out.
let output = input.map((el, index) => {
// If there is a previous index of this array, we need to join it with this one
if (input[index-1]) {
// all previous values including this one
let a = input.slice(0, index+1)
// concatenate them all with a seperator
let b = a.join('/');
return b;
} else {
// if not just return the element
return el;
}
})

You wrote: Please note that I'm currently working with ES5.
Unfortunately, some people do not understand anymore what is ES5 and suggest ES6 solutions (with arrow function expressions, let statements and constants).
Array.map was added to the ECMA-262 standard in the ECMAScript 5.1 edition. It is fully supported by all modern browsers inclusive IE9.
var input = ["apple", "banana", "pear", "kiwi", "orange"],
output = input.map(function(elem, index)
{
return index > 0 ? input.slice(0, index + 1).join('/') : elem;
});
console.log(JSON.stringify(output, null, '\t'));

var fruits = ["apple", "pear", "orange", "banana"];
var i;
for( i=0; i<fruits.length; i++) {
if (i == 0){
continue;
}
var temp = fruits[i];
fruits[i] = fruits[i-1] + "/" + temp;
}
for( i=0; i<fruits.length; i++) {
print(fruits[i]);
}
Here you go!
Points to remember:
Concatenation Operator
For loop
continue statement
Arrays

var array = ["apple", "banana", "pear", "kiwi", "orange"]
var all = [];
var str ="";
for(var i=0;i< array.length;i++)
{
if(array[i-1]){
str += array[i-1]+'/';
all.push(str+array[i])
}
else all.push(array[i])
}
console.log(all);

Time to .reduce it
This works by creating a new array, and accessing the last placed string and appending a '/' and then the next string current.
yourArray.reduce((newArray, current) => newArray.concat(newArray.length > 0 ? newArray[newArray.length - 1] + '/' + current : current), [])
// long version:
yourArray.reduce((newArray, current) => {
if (newArray.length > 0) {
return newArray.concat(current)
} else {
const previousString = newArray[newArray.length - 1]
return newArray.concat(previousString + '/' + current)
}
}, [])

For the ones that do use ES6 or can transpile the code to ES5 (Using i.e: Babel)
const a = ["a", "b", "c", "d", "e"];
const res = a.map((_, i) => a.slice(0, i+1).join("/"));
console.log(res);

Related

Search Array of strings for matching character sequence

I have an array like this
const arr = ["Apple", "Banana", "Cherry", "Orange", "Avocado", "Ananas", "Pineapple];
I need a function that returns an array with all the Elements from arr, that match the given character sequence. The order of the characters is of importance.
Given "ppl" the function should return ["Apple", "Pineapple"].
Given "n" the function should return ["Banana", "Orange", "Ananas", "Pineapple"].
Given "voca" the function shoould return ["Avocado"]
Given "rr" the function should return ["Cherry"], while given a "r" the function should return ["Cherry", "Orange"].
try this
const arr = ["Apple", "Banana", "Cherry", "Orange", "Avocado", "Ananas", "Pineapple"];
const search = query => arr.filter(s => s.toLowerCase().includes(query))
console.log(search("n"))
console.log(search("ppl"))
It is also possible like this
const arr = ["Apple", "Banana", "Cherry", "Orange", "Avocado", "Ananas", "Pineapple"];
const query = 'pp';
arr.filter(element => element.includes(query));
It's pretty straight forward using filter function and indexOf
const arr = ["Apple", "Banana", "Cherry", "Orange", "Avocado", "Ananas", "Pineapple"];
const cond = 'ppl'
console.log(arr.filter(x => x.indexOf(cond) > -1 ))
<script>
function checkPattern(str, pattern) {
var len = pattern.length;
if (str.length < len) {
return false;
}
for (var i = 0; i < len - 1; i++) {
var x = pattern[i];
var y = pattern[i + 1];
var last = str.lastIndexOf(x);
var first = str.indexOf(y);
if (last === -1 || first === -1 || last > first) {
return false;
}
}
return true;
}
var str = "engineers rock";
var pattern = "gin";
document.write(checkPattern(str, pattern));
</script>
You can use Array.prototype.filter() combined with String.prototype.includes():
const result = arr.filter(el => el.toLowerCase().includes(input))
Code:
const arr = ["Apple", "Banana", "Cherry", "Orange", "Avocado", "Ananas", "Pineapple"]
const inputs = ["ppl", "n", "voca", "rr", "r"]
inputs.forEach(input => {
const result = arr.filter(el => el.toLowerCase().includes(input))
console.log(`Result for ${input}:`, result)
})

How to concatenate previous string of an array with the next one?

I'm having trouble wrapping my head around this, but let's say there an array with these elements:
["apple", "banana", "pear", "kiwi", "orange"]
I would like to transfer this array into:
["apple", "apple/banana", "apple/banana/pear", "apple/banana/pear/kiwi", "apple/banana/pear/kiwi/orange"]
I need this in JavaScript and I'm not sure how to achieve it.
Please note that I'm currently working with ES5.
Here's a simple implementation of what you're trying to do :
ES5
var input = ["apple", "banana", "pear", "kiwi", "orange"];
var prev = '';
var output = input.map(function (el) {
el = prev + el; prev = el + '/'; return el;
});
console.log(output);
ES6
let input = ["apple", "banana", "pear", "kiwi", "orange"];
let prev= '';
let output = input.map( el => { el = prev + el; prev = el+'/'; return el})
console.log(output)
Array.map() is meant for these problems.
The map() method creates a new array with the results of calling a provided function on every element in the calling array.
And while walking through the array with map you can use join() and slice() to concatenate certain values from an original array.
let input = ["apple", "banana", "pear", "kiwi", "orange"];
let output = input.map((el, index) => {
return (input[index-1]) ? input.slice(0, index+1).join('/') : el;
})
output:
Array [
"apple",
"apple/banana",
"apple/banana/pear",
"apple/banana/pear/kiwi",
"apple/banana/pear/kiwi/orange"
]
Some more explanation on what is happening in those 3 lines:
// let's write it out.
let output = input.map((el, index) => {
// If there is a previous index of this array, we need to join it with this one
if (input[index-1]) {
// all previous values including this one
let a = input.slice(0, index+1)
// concatenate them all with a seperator
let b = a.join('/');
return b;
} else {
// if not just return the element
return el;
}
})
You wrote: Please note that I'm currently working with ES5.
Unfortunately, some people do not understand anymore what is ES5 and suggest ES6 solutions (with arrow function expressions, let statements and constants).
Array.map was added to the ECMA-262 standard in the ECMAScript 5.1 edition. It is fully supported by all modern browsers inclusive IE9.
var input = ["apple", "banana", "pear", "kiwi", "orange"],
output = input.map(function(elem, index)
{
return index > 0 ? input.slice(0, index + 1).join('/') : elem;
});
console.log(JSON.stringify(output, null, '\t'));
var fruits = ["apple", "pear", "orange", "banana"];
var i;
for( i=0; i<fruits.length; i++) {
if (i == 0){
continue;
}
var temp = fruits[i];
fruits[i] = fruits[i-1] + "/" + temp;
}
for( i=0; i<fruits.length; i++) {
print(fruits[i]);
}
Here you go!
Points to remember:
Concatenation Operator
For loop
continue statement
Arrays
var array = ["apple", "banana", "pear", "kiwi", "orange"]
var all = [];
var str ="";
for(var i=0;i< array.length;i++)
{
if(array[i-1]){
str += array[i-1]+'/';
all.push(str+array[i])
}
else all.push(array[i])
}
console.log(all);
Time to .reduce it
This works by creating a new array, and accessing the last placed string and appending a '/' and then the next string current.
yourArray.reduce((newArray, current) => newArray.concat(newArray.length > 0 ? newArray[newArray.length - 1] + '/' + current : current), [])
// long version:
yourArray.reduce((newArray, current) => {
if (newArray.length > 0) {
return newArray.concat(current)
} else {
const previousString = newArray[newArray.length - 1]
return newArray.concat(previousString + '/' + current)
}
}, [])
For the ones that do use ES6 or can transpile the code to ES5 (Using i.e: Babel)
const a = ["a", "b", "c", "d", "e"];
const res = a.map((_, i) => a.slice(0, i+1).join("/"));
console.log(res);

Regex and Array: Most efficient approach

I want to get all words with <=3 letters from an array.
Is iterating the array and checking every entry an efficient approach?
arr = ["cat", "apple", "window", "dog"];
for(i=0; i<arr.length; i++){
if(arr[i].match(/^[a-z]{3}$/)){
console.log(arr[i])
}
}
//returns: "cat" and "dog"
Or is there already a built-in function that does the job for me, so I don't have to explicitly define a for-loop and and if-statement.
No need to regex, try this:
var arr = ["cat", "apple", "window", "dog"];
var len = arr.length;
for(len; len<=0; len--){
if(arr[len].length <= 3){
console.log(arr[len]);
}
}
Edit: If you don't want to explicitly define a for-loop and and if statement then try using .filter() and .match():
var arr = ["cat", "apple", "window", "dog"];
var AcceptedItems = arr.filter(function(item) {
return item.match(/^[a-z]{1,3}$/);
});
I assume you want to return words that are even like '1abc' since it has only 3 letters.
The below will work, using filter function of an array.
arr = ["cat", "apple", "window", "dog", "1acb", "1abcd"];
function getLessThanThree(anArray){
return anArray.filter(function(v){
return !( /[a-zA-Z]{3}./.exec(v) );
})
}
console.log(getLessThanThree(arr)); // logs [ 'cat', 'dog', '1acb' ]
Test it here
If you want to get items matching something in array you need to iterate it.
Anyway, since ECMA-Script 5 you would refactor your code as follows:
var results = arr.filter(function(item) { return item.lengh <= 3; });
Or in ECMA-Script 6 and above:
var results = arr.filter(item => item.length <= 3);
In terms of productivity, you're going to be faster.
You're in JavaScript. It can already do this, no regexp required.
var arr = ["cat", "apple", "window", "dog"];
var filtered = arr.filter(function(e) { return e.length <= 3; });
done. Use ES6 for even simpler syntax:
var filtered = arr.filter(e => e.length <= 3);
Lots of ways to skin this cat, I like:
var arr = ["cat", "apple", "window", "dog"];
var upToThreeLetters = function(word) {
return word.length <= 3;
}
var filteredArr = arr.filter(upToThreeLetters);

Extracting intersection between two javascript arrays [duplicate]

This question already has answers here:
Simplest code for array intersection in javascript
(40 answers)
Closed 3 years ago.
I have two arrays, and I want to be able to compare the two and only return the values that match. For example both arrays have the value cat so that is what will be returned. I haven't found anything like this. What would be the best way to return similarities?
var array1 = ["cat", "sum","fun", "run"];
var array2 = ["bat", "cat","dog","sun", "hut", "gut"];
//if value in array1 is equal to value in array2 then return match: cat
You can use :
const intersection = array1.filter(element => array2.includes(element));
Naturally, my approach was to loop through the first array once and check the index of each value in the second array. If the index is > -1, then push it onto the returned array.
​Array.prototype.diff = function(arr2) {
var ret = [];
for(var i in this) {
if(arr2.indexOf(this[i]) > -1){
ret.push(this[i]);
}
}
return ret;
};
​
My solution doesn't use two loops like others do so it may run a bit faster. If you want to avoid using for..in, you can sort both arrays first to reindex all their values:
Array.prototype.diff = function(arr2) {
var ret = [];
this.sort();
arr2.sort();
for(var i = 0; i < this.length; i += 1) {
if(arr2.indexOf(this[i]) > -1){
ret.push(this[i]);
}
}
return ret;
};
Usage would look like:
var array1 = ["cat", "sum","fun", "run", "hut"];
var array2 = ["bat", "cat","dog","sun", "hut", "gut"];
console.log(array1.diff(array2));
If you have an issue/problem with extending the Array prototype, you could easily change this to a function.
var diff = function(arr, arr2) {
And you'd change anywhere where the func originally said this to arr2.
I found a slight alteration on what #jota3 suggested worked perfectly for me.
var intersections = array1.filter(e => array2.indexOf(e) !== -1);
Hope this helps!
This function runs in O(n log(n) + m log(m)) compared to O(n*m) (as seen in the other solutions with loops/indexOf) which can be useful if you are dealing with lots of values.
However, because neither "a" > 1 nor "a" < 1, this only works for elements of the same type.
function intersect_arrays(a, b) {
var sorted_a = a.concat().sort();
var sorted_b = b.concat().sort();
var common = [];
var a_i = 0;
var b_i = 0;
while (a_i < a.length
&& b_i < b.length)
{
if (sorted_a[a_i] === sorted_b[b_i]) {
common.push(sorted_a[a_i]);
a_i++;
b_i++;
}
else if(sorted_a[a_i] < sorted_b[b_i]) {
a_i++;
}
else {
b_i++;
}
}
return common;
}
Example:
var array1 = ["cat", "sum", "fun", "hut"], //modified for additional match
array2 = ["bat", "cat", "dog", "sun", "hut", "gut"];
intersect_arrays(array1, array2);
>> ["cat", "hut"]
Loop through the second array each time you iterate over an element in the first array, then check for matches.
var array1 = ["cat", "sum", "fun", "run"],
array2 = ["bat", "cat", "dog", "sun", "hut", "gut"];
function getMatch(a, b) {
var matches = [];
for ( var i = 0; i < a.length; i++ ) {
for ( var e = 0; e < b.length; e++ ) {
if ( a[i] === b[e] ) matches.push( a[i] );
}
}
return matches;
}
getMatch(array1, array2); // ["cat"]
var array1 = [1, 2, 3, 4, 5, 6];
var array2 = [1, 2, 3, 4, 5, 6, 7, 8, 9];
var array3 = array2.filter(function(obj) {
return array1.indexOf(obj) !== -1;
});
You can use javascript function .find()
As it says in MDN, it will return the first value that is true. If such an element is found, find immediately returns the value of that element. Otherwise, find returns undefined.
var array1 = ["cat", "sum", "fun", "run", "cat"];
var array2 = ["bat", "cat", "dog", "sun", "hut", "gut"];
found = array1.find((val, index) => {
console.log('index', index) // Stops at 0
return array2.includes(val)
})
console.log(found)
Or use .filter(), which loops through every elements first, then give back the result to you.
var array1 = ["cat", "sum", "fun", "run", "cat"];
var array2 = ["bat", "cat", "dog", "sun", "hut", "gut"];
found = array1.filter((val, index) => {
console.log('index', index) // Stops at array1.length - 1
return array2.includes(val)
})
console.log(found)
use lodash
GLOBAL.utils = require('lodash')
var arr1 = ['first' , 'second'];
var arr2 = ['second '];
var result = utils.difference(arr1 , arr2);
console.log ( "result :" + result );
Libraries like underscore and lodash have a utility method called intersection to find matches in arrays passed in. Take a look at: http://underscorejs.org/#intersection
Done as a answer so I can do formatting...
This is the the process you need to go through. Looping through an array for the specifics.
create an empty array
loop through array1, element by element. {
loop through array2, element by element {
if array1.element == array2.element {
add to your new array
}
}
}
If your values are non-null strings or numbers, you can use an object as a dictionary:
var map = {}, result = [], i;
for (i = 0; i < array1.length; ++i) {
map[array1[i]] = 1;
}
for (i = 0; i < array2.length; ++i) {
if (map[array2[i]] === 1) {
result.push(array2[i]);
// avoid returning a value twice if it appears twice in array 2
map[array2[i]] = 0;
}
}
return result;
With some ES6:
let sortedArray = [];
firstArr.map((first) => {
sortedArray[defaultArray.findIndex(def => def === first)] = first;
});
sortedArray = sortedArray.filter(v => v);
This snippet also sorts the firstArr based on the order of the defaultArray
like:
let firstArr = ['apple', 'kiwi', 'banana'];
let defaultArray = ['kiwi', 'apple', 'pear'];
...
console.log(sortedArray);
// ['kiwi', 'apple'];
Iterate on array1 and find the indexof element present in array2.
var array1 = ["cat", "sum","fun", "run"];
var array2 = ["bat", "cat","sun", "hut", "gut"];
var str='';
for(var i=0;i<array1.length;i++){
if(array2.indexOf(array1[i]) != -1){
str+=array1[i]+' ';
};
}
console.log(str)

How do I return array of duplicate strings in array?

I need a function that takes in an array and will return an array with all the duplicates. I would prefer to use underscore if possible.
given the array:
[
"apple",
"apple",
"pear",
"pear",
"kiwi",
"peach"
]
I need to return an array
[
"apple",
"pear"
]
Many of the methods I've found will return a boolean and not an array of the duplicates.
For example
var fruits = ["apple","apple"];
var uniq_fruits = _.uniq(fruits);
var duplicates_exist = (fruits.length == uniq_fruits.length);
You could use _.countBy to get the word frequencies and then use _.reduce to collect up the values with a frequency greater than one:
function collect_dups(a, n, word) {
if(n > 1)
a.push(word);
return a;
}
var dups = _(words).chain()
.countBy()
.reduce(collect_dups, [])
.value();
Demo: http://jsfiddle.net/ambiguous/gKmfh/1/
Turn your list into a map, then turn the map into a list.
var fruits = ["apple", // ... ];
function fruitCounter(countMap, fruit) {
if (countMap[fruit] == null)
countMap[fruit] = 1;
else
countMap[fruit]++;
return countMap;
}
function dupFinder(dupList, count, fruit) {
if (count > 1)
dupList.push(fruit);
return dupList;
}
var dups = _.reduce(_.reduce(fruits, fruitCounter, {}), dupFinder, []);
It's sort-of unfortunate that there's nothing really like "filter" for the properties of an object, but it's not too bad with "reduce".
edit — a comment from someone better at Underscore than me points out that the inner "reduce" could be replaced by a simpler "countBy":
var dups = _.reduce(_.countBy(fruits, function(f) { return f; }), dupFinder, []);
var common = function(array){
var tally = function(array){
var make_object = {};
_.each(array, function(item){
make_object[item] = (typeof make_object[item] == "undefined") ? 1 : make_object[item] + 1;
});
return make_object;
}(array);
var duplicates = function(obj){
var duplicates = [];
_.each(obj, function(value, key){
if(value > 1){
duplicates.push(key);
}
});
return duplicates;
}(tally);
return duplicates;
};
The idea is very straight forward. Group the items by its value and then find which group having more than 1 items. Finally pick only one item from each group.
lst = [ "apple", "apple", "pear", "pear", "kiwi", "peach"];
var result = _.chain(lst)
.groupBy(function (i) { return i; })
.filter(function (v, k) { return v.length > 1; })
.map(function(v){return v[0]; })
.value();
>>["apple", "pear"]
where arr is your input, you just check to see if the element is a key on the obj object - if it is, pass it to the output array and reloop, otherwise add the key to the object:
function findDupes(arr) {
var obj = {}, newArr = [];
for (var i = 0, l = arr.length; i < l; i++) {
if (obj[arr[i]]) { newArr.push(arr[i]); continue; }
obj[arr[i]] = true;
}
return newArr;
}
var dupes = findDupes(arr);
Giving you have a simple one level array of strings, I would suggest to sort an array first and then loop through it trying to compare current item with the next one.
Something like this:
var fruit = [
"apple",
"apple",
"apple",
"pear",
"pear",
"cantalope"
];
var common = function(array){
var mySortedArray = array.sort();
var myResultArray = [];
for (var i = 0; i < mySortedArray.length - 1; i++)
if ( (mySortedArray[i + 1] == mySortedArray[i]) &&
(mySortedArray[i] != myResultArray[myResultArray.length-1]) )
myResultArray.push(mySortedArray[i]);
return myResultArray;
};
alert(common(fruit));
I started from this function : https://stackoverflow.com/a/840849/1636522
function getDuplicates(arr) {
var i,
len = arr.length,
out = [],
obj = {};
for (i = 0; i < len; i++) {
switch (obj[arr[i]]) {
case undefined: obj[arr[i]] = 1; break;
case 1: obj[arr[i]] = 2; out.push(arr[i]); break;
}
}
return out;
}

Categories