Doing the DNA challenge and so close but clearly misunderstanding prototype.split(""). What's the best way to turn these strings ["AC", "CA", "TA"] into subarrays? [["A","C"]["C","A"]["T","A"]]
function pairElement(str) {
//break into array
var arr = str.split("");
//add new letter (could be refactored as switch)
for (i = 0; i < arr.length; i++) {
if (arr[i] == "G") {
arr[i] += "C";
} else if (arr[i] == "C") {
arr[i] += "G";
} else if (arr[i] == "T") {
arr[i] += "A";
} else if (arr[i] == "A") {
arr[i] += "T";
}
}
//break into arrays again
//this is how I'm trying to use.split to break it up. Doesn't work.
var broken = [];
for (x = 0; x < arr.length; x++) {
broken += arr[x].split("");
}
//return
return arr;
}
console.log(pairElement("GCG"));
you can use .map and split them by ""
var o = ["AC", "CA", "TA"];
var s = o.map(e=> e.split(""));
console.log(s)
You actually have to just push the split result in the broken array and return it !
function pairElement(str) {
//break into array
var arr = str.split("");
//add new letter (could be refactored as switch)
for (i = 0; i < arr.length; i++) {
if (arr[i] == "G") {
arr[i] += "C";
} else if (arr[i] == "C") {
arr[i] += "G";
} else if (arr[i] == "T") {
arr[i] += "A";
} else if (arr[i] == "A") {
arr[i] += "T";
}
}
//break into arrays again
//this is how I'm trying to use.split to break it up. Doesn't work.
var broken = [];
for (x = 0; x < arr.length; x++) {
broken.push(arr[x].split(""));
}
//return
return broken;
}
console.log(pairElement("GCG"));
To answer your 'what's the best way' question, map your arrays into the split versions of themselves:
const subarrays = array.map(pair => pair.split());
Very simple in functional style:
> seq = ['AC', 'CA', 'TA']
[ 'AC', 'CA', 'TA' ]
> seq.map(s => s.split(''))
[ [ 'A', 'C' ], [ 'C', 'A' ], [ 'T', 'A' ] ]
Overall, I'd do some refactoring on the whole function:
var m = new Map([["G", "C"], ["C", "G"], ["A", "T"], ["T", "A"]]);
function pairElement(str) {
return [...str].map(c => [c, m.get(c)]);
}
console.log(pairElement("GCG"));
And if there's a guarantee that the sub-arrays are never mutated, then you can save a good bit of memory by reusing arrays instead of creating them over and over.
var m = new Map([["G", ["G", "C"]], ["C", ["C", "G"]], ["A", ["A", "T"]], ["T", ["T", "A"]]]);
function pairElement(str) {
return [...str].map(c => m.get(c));
}
console.log(pairElement("GCG"));
But to directly answer your question, you can do it without explicit .split() calls. Since you know there's always two characters, you can use parameter destructuring on the strings.
var arr = ["AC", "CA", "TA"];
var s = arr.map(([a, b]) => [a, b]);
console.log(s)
Or even a little shorter using rest syntax, like this:
var arr = ["AC", "CA", "TA"];
var s = arr.map(([...a]) => a);
console.log(s)
Or using spread syntax in an array literal:
var arr = ["AC", "CA", "TA"];
var s = arr.map(s => [...s]);
console.log(s)
Related
I am trying to combine items in an array, with every item below it. It should make a set of the current character and each character below it, and iteratively walk down the array. For example, if I have an array like this:
var myArray = ['A','B','C','D']
I would like an output like this:
AB AC AD BC BD CD
The code I have is getting me close, but I am having a hard time figuring out the rest. Here is what I have so far:
var myArray = ['A', 'B', 'C', 'D']
var sql_parts = []
var string = "";
for (var i = 0; i < myArray.length; i++) {
recurse_function(string, i)
}
console.log(sql_parts)
function recurse_function(string_val, count) {
if ((myArray.length - count) == 0) {
return string_val;
} else {
string_val += myArray[count]
sql_parts.push(string_val)
recurse_function(string_val, count + 1)
}
}
But this produces:
["A", "AB", "ABC", "ABCD", "B", "BC", "BCD", "C", "CD", "D"]
Here is one solution:
Define the recursive function to take the array and an empty list initially to store the combinations
The base condition is when the array is empty or has one element
Otherwise, Remove the first element "start"
Iterate over the array to store its combinations with its following elements
Recur again with array and combinations updated
function recurse_function(array, combinations = []) {
if(array.length <= 1) return combinations;
const start = array.shift();
for(let i = 0; i < array.length; i++) combinations.push(`${start}${array[i]}`);
return recurse_function(array, combinations);
}
console.log( recurse_function(['A','B','C','D']) );
var myArray = ['A','B','C','D']
var sql_parts = []
for(var i =0; i< myArray.length; i++){
var a = myArray[i]
for(var j = i+1; j<myArray.length; j++){
var b=myArray[j]
var c= a+b
sql_parts.push(c)
}
}
I think this is something that you're looking for, it's a function that is very cheap on resources. Its not recursive (why you now would need something like that for this simple scenario)
var myArray = ['A','B','C','D']
let [a, b, iter] = [0, 1, 2]
let result = []
for (;a < myArray.length; a++) {
for (;b < myArray.length; b++) {
result.push(myArray[a]+myArray[b])
}
b = iter++
}
console.log(result)
I don't think you need to recurse in this particular case. You can simply combine the current element with the following ones with flatMap:
['A','B','C','D'].flatMap((x, i, xs) => xs.slice(i+1).map(y => x+y));
//=> ["AB", "AC", "AD", "BC", "BD", "CD"]
var myArray = ['A', 'B', 'C', 'D'];
var result = [];
myArray.forEach((item, index) => {
myArray.forEach((item2, index2) => (index < index2 ? result.push(item + item2) : ''));
});
console.log(result);
I'm trying to complete a HackerRank challenge that involves printing a list of elements of an array starting with all the vowels then all the consonants but I'm having trouble with that.
function vowelsAndConsonants(s) {
var str = s;
var arr = str.split("");
var i;
var vow = ["a","e","i","o","u","y"];
var con = ['b','c','d','f','g','h','j','k','l','m','n','p','q','r','s','t','v','w','x','z']
for (i = 0; i < arr.length; i++) {
for (var j = 0; j< vow.length; j++){
if (arr[i] === vow[j]){
console.log(arr[i])
}
}
}
}
This is what I get from the code above, but I can't print the consonants. The input string is "javascriptloops"
a
a
i
o
o
I also tried this
function vowelsAndConsonants(s) {
var str = s;
var arr = str.split("");
var i;
var vow = ["a","e","i","o","u","y"];
var con = ['b','c','d','f','g','h','j','k','l','m','n','p','q','r','s','t','v','w','x','z']
for (i = 0; i < arr.length; i++) {
for (var j = 0; j< vow.length; j++){
if (arr[i] === vow[j]){
console.log(arr[i])
break;
}
}
for (var j = 0; j< con.length; j++){
if (arr[i] === con[j]){
console.log(arr[i])
}
}
}
}
But here's what I had
j
a
v
a
s
c
r
i
p
t
l
o
o
p
s
An easy solution would be looping through twice:
function vowelsAndConsonants(s) {
let vowels = ["a", "e", "i", "o", "u"];
for(let v of s) {
if(vowels.includes(v))
console.log(v);
}
for(let v of s) {
if(!vowels.includes(v))
console.log(v);
}
}
It's a good idea to define the smaller subset (vowels) and treat the rest of the letters of the alphabet as consonants.
Also, naming your variables goes a long way in readability
function vowelsAndConsonants(s) {
var letters = s.split("");
const vowels = ["a", "e", "i", "o", "u", "y"];
for (const letter of letters) { // we are cycling through the letters to find all vowels
for (const vowel of vowels) { // now we are cycling through the list of vowels
if (letter === vowel) { // if we found a vowel in the vowel list, print it and stop searching for other vowels (break)
console.log(letter);
break;
}
}
}
// Searching for consonants is trickier
for (const letter of letters) { // we cycle again through the letters
let consonant = true; // we assume that the letter is consonant until it's proven otherwise
for (const vowel of vowels) { // cycling through the list of vowels
if (letter === vowel) { // if we found that the letter is vowel
consonant = false; // we set the flag to false
break; // and stop searching more as we know already that it is a vowel
}
}
if (consonant === true) { // if after cycling we realized that this is a consonant, and not a vowel - print it
console.log(letter)
}
}
}
vowelsAndConsonants("normal");
there is a solution, you can take a look
function vowelsAndConsonants(s) {
var str = s;
var arr = str.split("");
var vow = ["a","e","i","o","u","y"];
const ordered = arr.reduce( (res, letter) => {
if (vow.includes(letter)) {
return {...res, vow: [...res.vow, letter]}
}
return {...res, con: [...res.con, letter]}
}, { con: [], vow: []});
return ordered.vow.join('') + ordered.con.join('');
}
Your outer loop needs to run twice.
This solution also uses for ... in loops and array.includes(), which is a little cleaner than nesting standard for loops.
const vowelsAndConsonants = s => {
const vow = ['a','e','i','o','u','y'];
for (const c of s)
if (vow.includes(c))
console.log(c)
for (const c of s)
if (!vow.includes(c))
console.log(c)
}
vowelsAndConsonants('javascriptloops')
You can use filter() instead of loops:
var vow = ['a','e','i','o','u','y'].join('');
var str = 'javascriptloops'.split('');
console.log(str.filter(x => vow.includes(x))); // vowels
console.log(str.filter(x => !vow.includes(x))); // consonants (not vowels)
const f = s => {
const isVowel = char => ['a', 'e', 'i', 'o', 'u'].includes(char);
const letters = s.split('');
const consonants = letters.reduce((result, letter) => {
if (isVowel(letter)) console.log(letter);
else result.push(letter);
return result;
}, []);
consonants.forEach(c => console.log(c))
}
f('javascriptloops');
Given an array or object with n keys, I need to find all combinations with length x.
Given X is variable. binomial_coefficient(n,x).
Currently I'm using this:
function combine(items) {
var result = [];
var f = function(prefix, items) {
for (var i = 0; i < items.length; i++) {
result.push(prefix + items[i]);
f(prefix + items[i], items.slice(i + 1));
}
}
f('', items);
return result;
}
var combinations = combine(["a", "b", "c", "d"]);
The output is:
["a", "ab", "abc", "abcd", "abd", "ac", "acd", "ad", "b", "bc", "bcd", "bd", "c", "cd", "d"]
So if I want the binomial coefficient x=3 from n=4 I select all the strings with length equal to three. {abc, abd, acd, bcd}.
So I do this in two steps.
Is there a more efficient algorithm with smaller complexity?
Link: Solution performance (JSPerf)
Your algorithm is almost O(2^n), you can discard a lot of combinations, but the num of elements will be (n! * (n-x)!) / x!.
To discard the useless combinations you can use an indexed array.
function combine(items, numSubItems) {
var result = [];
var indexes = new Array(numSubItems);
for (var i = 0 ; i < numSubItems; i++) {
indexes[i] = i;
}
while (indexes[0] < (items.length - numSubItems + 1)) {
var v = [];
for (var i = 0 ; i < numSubItems; i++) {
v.push(items[indexes[i]]);
}
result.push(v);
indexes[numSubItems - 1]++;
var l = numSubItems - 1; // reference always is the last position at beginning
while ( (indexes[numSubItems - 1] >= items.length) && (indexes[0] < items.length - numSubItems + 1)) {
l--; // the last position is reached
indexes[l]++;
for (var i = l +1 ; i < numSubItems; i++) {
indexes[i] = indexes[l] + (i - l);
}
}
}
return result;
}
var combinations = combine(["a", "b", "c", "d"], 3);
console.log(JSON.stringify(combinations));
For example, the first combination have the indexes: [0, 1, 2] and the elements ["a", "b", "c"]. To compute the next combination, It get the last index 2 and try to increment, if the increment is lower than the max position (in this case 4), the next combination is reached, but if It is not, It must increment to a previous index.
You could use an iterative and recursive approach with stress on the length of the array and the still needed items.
Basically combine() takes an array with the values to combine and a size of the wanted combination results sets.
The inner function c() takes an array of previously made combinations and a start value as index of the original array for combination. The return is an array with all made combinations.
The first call is allways c([], 0), because of an empty result array and a start index of 0.
function combine(array, size) {
function c(part, start) {
var result = [], i, l, p;
for (i = start, l = array.length; i < l; i++) {
p = part.slice(0); // get a copy of part
p.push(array[i]); // add the iterated element to p
if (p.length < size) { // test if recursion can go on
result = result.concat(c(p, i + 1)); // call c again & concat rresult
} else {
result.push(p); // push p to result, stop recursion
}
}
return result;
}
return c([], 0);
}
console.log(combine(["a", "b", "c", "d"], 3));
.as-console-wrapper { max-height: 100% !important; top: 0; }
We could create just those combinations we are interested in. Also, rather than cloning arrays by using slice in each call, we can use a pointer to the original array. Here's one version. Converting it to recursion without an external global variable is left as an exercise.
function choose(ns,r){
var res = [];
function _choose(i,_res){
if (_res.length == r){
res.push(_res);
return;
} else if (_res.length + ns.length - i == r){
_res = _res.concat(ns.slice(i));
res.push(_res);
return
}
var temp = _res.slice();
temp.push(ns[i]);
_choose(i + 1,temp);
_choose(i + 1,_res);
}
_choose(0,[]);
return res;
}
var combinations = choose(["a", "b", "c", "d"], 3);
console.log(JSON.stringify(combinations));
And here's the true recursion.
function seq(a,b){
var res = [];
for (var i=a; i<=b; i++)
res.push(i);
return res;
}
function f(n,k){
if (k === 0)
return [[]];
if (n === k)
return [seq(1,n)];
let left = f(n - 1, k - 1),
right = f(n - 1, k);
for (let i=0; i<left.length; i++)
left[i].push(n);
return left.concat(right);
}
console.log(JSON.stringify(f(4,3)))
I've been trying to implement a function where given with two arrays,
array1's elements is used as conditions to filter out elements in array2.
For instance:
array1= [apple, grapes, oranges]
array2= [potato, pears, grapes, berries, apples, oranges]
After feeding into a function, array2 should have elements as such:
filter_twoArrays(array1,array2)
array2= [grapes, apples, oranges]
I've tried the following code, using for loops and array.splice(), but the problem I am seeing is that when I use the splice method, it seems that it changes the lengths of array2 in the for loop:
function filter_twoArrays(filter,result){
for(i=0; i< filter.length; i++){
for(j=0; j< result.length; j++){
if(filter[i] !== result[j]){
result.splice(j,1)
}
}
}
Any inputs will be greatly appreciated on how to refine the filter function
cheers!
You can use filter as follow
var array1 = ['apples', 'grapes', 'oranges', 'banana'],
array2 = ['potato', 'pears', 'grapes', 'berries', 'apples', 'oranges'];
var intersection = array1.filter(function(e) {
return array2.indexOf(e) > -1;
});
console.log(intersection);
You can also add this method on Array prototype and call it directly on array
Array.prototype.intersection = function(arr) {
return this.filter(function(e) {
return arr.indexOf(e) > -1;
});
};
var array1 = ['apples', 'grapes', 'oranges', 'banana'],
array2 = ['potato', 'pears', 'grapes', 'berries', 'apples', 'oranges'];
var intersection = array1.intersection(array2);
console.log(intersection);
You can use some, like this:
let newArray = array2.filter(
(array22) => !array1.some((array11) => array11.id === array22._id));
Hi this is a porting of the function array_intersect php. Should be good for you
http://phpjs.org/functions/array_intersect/
function array_intersect(arr1) {
// discuss at: http://phpjs.org/functions/array_intersect/
// original by: Brett Zamir (http://brett-zamir.me)
// note: These only output associative arrays (would need to be
// note: all numeric and counting from zero to be numeric)
// example 1: $array1 = {'a' : 'green', 0:'red', 1: 'blue'};
// example 1: $array2 = {'b' : 'green', 0:'yellow', 1:'red'};
// example 1: $array3 = ['green', 'red'];
// example 1: $result = array_intersect($array1, $array2, $array3);
// returns 1: {0: 'red', a: 'green'}
var retArr = {},
argl = arguments.length,
arglm1 = argl - 1,
k1 = '',
arr = {},
i = 0,
k = '';
arr1keys: for (k1 in arr1) {
arrs: for (i = 1; i < argl; i++) {
arr = arguments[i];
for (k in arr) {
if (arr[k] === arr1[k1]) {
if (i === arglm1) {
retArr[k1] = arr1[k1];
}
// If the innermost loop always leads at least once to an equal value, continue the loop until done
continue arrs;
}
}
// If it reaches here, it wasn't found in at least one array, so try next value
continue arr1keys;
}
}
return retArr;
}
You can use
const arr1 = [1, 2, 3];
const arr2 = [2, 3];
arr1.filter(e => arr2.indexOf(e) > -1 ? false : true); // [1]
Came here some week back to find a solution to a problem like this but its a pity I couldn't get what I wanted, but now I figured it out in a more simple way. using the arrow function, .filter() method and .includes() method.
Declare an arrow function that takes in two arguments:
const filterTwoArrays = (string1, string2) => string1.filter(item => string2.includes(item));
console.log(filterTwoArrays(array1, array2)).
Here is one simple way based on your code
function array_filter(filter, result) {
var filterLen = filter.length;
var resultLen = result.length;
for (i = 0; i < resultLen; i++) {
for (j = 0; j < filterLen; j++) {
if (!contains(filter, result[i]))
result.splice(i, 1);
}
}
}
//Return boolean depending if array 'a' contains item 'obj'
function contains(array, value) {
for (var i = 0; i < array.length; i++) {
if (array[i] == value) {
return true;
}
}
return false;
}
Since you have tagged javascript here is the solution.
function f1(x, y) {
var t = y.slice(0);
var r = [];
for (var i = 0; i < x.length; i++) {
for (var j = 0; j < y.length; j++) {
if (x[i] === y[j]) {
[].push.apply(r, t.splice(j, 1));
}
}
}
console.log(r)
y.length = 0;
[].push.apply(y, r);
}
Mark the items which are to be filtered out via delete result[index] manipulate them as needed.
JavaScript
window.onload = runs;
function runs() {
var array1 = ["apples", "grapes", "oranges"];
var array2 = ["potato", "pears", "grapes", "berries", "apples", "oranges"];
var result = filter_twoArrays(array1, array2);
function filter_twoArrays(filter, result) {
var i = 0,
j = 0;
for (i = 0; i < result.length; i++) {
var FLAG = 0;
for (j = 0; j < filter.length; j++) {
if (filter[j] == result[i]) {
FLAG = 1;
}
}
if (FLAG == 0) delete result[i];
}
return result;
}
var body = document.getElementsByTagName("body")[0];
var i = 0;
for (i = 0; i < result.length; i++) {
if (result[i] !== undefined)
body.innerHTML = body.innerHTML + result[i] + " ";
}
}
const func = array1.filter(item => array2.includes(item));
I have two javascript array and I need to compare them. For example, suppose I have these two arrays:
var array1 = ["1", "2", "3", "4"];
var array2 = ["4", "1", "3", "2"];
These arrays are equal in fact and I want to get true as a result of comparison. What is the best and fastest way for doing that?
What you really have are two sets, not arrays, but unfortunately JavaScript does not provide any sort of "set" datatype. The easiest way to do this type of check is by using some sort of functional JavaScript library, such as lodash.
Using lodash's _.union function makes this trivially easy.
function setsEqual(a, b) {
var u = _.union(a, b);
return u.length === a.length && u.length === b.length;
}
If you want to do this without external libraries, you can do so using Array.prototype.every.
function setsEqual(a, b) {
return a.length === b.length
&& a.every(function (v) { return b.indexOf(v) !== -1; });
}
The best way and fastest way to do this is using object which keep tracks the value of and its count. Then we can see if it exist in second array. Try this
function compare(arr1, arr2){
var obj={}, len = arr1.length, i=0, isSame=true, prop;
if(arr1.length === arr2.length){
for(;i<len;i++){
if(obj[arr1[i]]){
obj[arr1[i]] = obj[arr1[i]]+1;
} else{
obj[arr1[i]] =1;
}
}
i=0, len = arr2.length;
for(;i<len;i++){
if(obj[arr2[i]]){
obj[arr2[i]] = obj[arr2[i]]-1;
} else{
isSame = false;
break;
}
}
for (prop in obj){
if(obj[prop] > 0){
isSame = false;
break;
}
}
}else{
isSame = false;
}
return isSame;
}
Try removing matching elements until both elements are empty:
var array1 = ["1", "2", "3", "4", "1", "5"];
var array2 = ["1", "5", "2", "3", "4", "1"];
var isSame = false;
if(array1.length != array2.length)
isSame = false;
else
{
for(var i = 0; i < array1.length; i ++)
{
var removed = false;
for(var j = 0; j < array2.length; j ++)
{
if(array2[j] == array1[i])
{
// remove from array2
array1.splice(i, 1);
// remove from array1
array2.splice(j, 1);
// go back 1 for i
removed = true;
i --;
break;
}
}
if(!removed)
break;
}
if(array1.length == 0 && array2.length == 0)
isSame = true;
}
I don't suppose that is a fastest approach but it can be useful for a little arrays with primitives
function compareArrays(a, b) {
var copyA = a.slice(),
copyB = b.slice();
if (a.length !== b.length) { return false; }
return copyA.sort().toString() === copyB.sort().toString();
}
Return status from function after comparing two array.
arr1 = [101,12,13,10,4];
arr2 = [101,4,12,13,10];
function compareTwoArray(arr1, arr2) {
return arr1.length === arr2.length &&
arr1.sort().every((val, index)=> val === arr2.sort()[index]);
}
console.log(compareTwoArray(arr1, arr2))