CodeWars Javascript challenge: IndexOf Array in Array - javascript

I'm trying to complete this exercise from codewars. The instructions say: " Write a function that looks for an array within a two-dimensional array and returns the index of the first matching element. If there is no match, your function should return -1"
Exemples:
var arrayToSearch = [[1,2],[3,4],[5,6]];
var query = [1,2]; // => 0
query = [5,6]; // => 2
query = [9,2]; // => -1
This is my solution, but it still fails.
var searchArray = function (arrayToSearch, query) {
for(i = 0; i < arrayToSearch.length; i++) {
for (j = 0; j < arrayToSearch[i]; j++) {
if (arrayToSearch[i][j] === query) {
return i;
}
}
}
return -1;
}
I'm not sure what I'm doing wrong, but I think the problem is in the if statement, but I don't know what it is.

Issue in logic.
Your second if condition j < arrayToSearch[i] will always returns false, because you are comparing a number j against an array arrayToSearch[i]. In this case the number j will be compared agaist the first elementin the array arrayToSearch, which makes the function always returns -1.
Corrected Code
var arrayToSearch = [[1, 2], [3, 4], [5, 6]];
var query = [1, 2]; // => 0
// query = [5, 6]; // => 2
// query = [9, 2]; // => -1
var searchArray = function (arrayToSearch, query) {
for (i = 0; i < arrayToSearch.length; i++) {
let isEqual = true;
for (j = 0; j < arrayToSearch[i].length; j++) {
isEqual = isEqual && (arrayToSearch[i][j] === query[j])
}
if (isEqual) {
return i;
}
}
return -1;
}
console.log(searchArray(arrayToSearch, query));

this simple code will work.
var arrayToSearch = [[1,2],[3,4],[5,6]];
var query = [1,2];
var searchArray = function (arrayToSearch, query) {
for (var i = 0; i < arrayToSearch.length; i++) {
if (arrayToSearch[i][0] == query[0] && arrayToSearch[i][1] == query[1]) {
return true;
}
}
return -1;
}

One-liner if you don't mind:
const arrayToSearch = [[1,2],[3,4],[5,6]];
const query1 = [1,2];
const query2 = [3,4];
const query3 = [5,6];
const query4 = [9,2];
const searchArray = (arr, query) => arr.map(e => e.toString()).indexOf(query.toString());
console.log(`[${query1}]:`, searchArray(arrayToSearch, query1));
console.log(`[${query2}]:`, searchArray(arrayToSearch, query2));
console.log(`[${query3}]:`, searchArray(arrayToSearch, query3));
console.log(`[${query4}]:`, searchArray(arrayToSearch, query4));
.as-console-wrapper{min-height: 100%!important; top: 0}

Related

How to split array into equal parts based on values?

Input Arr=[1,2,3,4,5,6,7,8,9,10]
Expected output:-
Arr1 = [1,2,3,4,5,6,7] = 28
Arr2 = [8,9,10] = 27
The sum of arrays should be almost the same..
It can also be 3 or more parts
How to achieve this via custom function?
let Arr = [1,2,3,4,5,6,7,8,9,10]
const numberOfParts = 2
function SplitArr(Array, Parts){
/* ... */
}
let result = SplitArr(Arr,numberOfParts)
/* result should be [[1,2,3,4,5,6,7],[8,9,10]] */
/* output can be in any format as long as it can get the parts */
I think you can't do that directly by JS functions.
You have to create a custom function to achieve this.
I have considered dividing the array into 2 equal parts.
You can't always split the array equally. Here in this array, you can't partition array into more than 2 subparts, otherwise it will give more than 3 parts as some of the elements are present there having sum more than the partitioned Sum.
Note: I treated the array to be sorted, otherwise it depends on the usecase.
Note: I have updated the old implementation based on the updated question requirement
let arr=[1,2,3,4,5,6,7,8,9,10]
function splitArrayEqually(arr, parts=2){
//get the total sum of the array
let sum = arr.reduce((currentSum, value) => currentSum+value ,0);
//get the half sum of the array
let partitionedSum = Math.ceil(sum/parts);
let start=0, end=0, currentSum=0;
let splittedArray=[];
//get the index till which the sum is less then equal partitioned sum
while(end < arr.length){
if(currentSum+arr[end] > partitionedSum){
splittedArray.push(arr.slice(start,end));
start = end; //start new window from current index
currentSum = 0; //make sum =0
}
//add current end index to sum
currentSum += arr[end];
end++;
}
splittedArray.push(arr.slice(start));
return splittedArray;
}
splitted = splitArrayEqually(arr,3);
console.log(splitted)
let Arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
const numberOfParts = 3
function sumOfArray(arr) {
if (arr) {
if (arr.length > 0) {
let sum = 0
for (let i = 0; i < arr.length; i++) sum += arr[i]
return sum
} else {
return 0
}
} else {
return 0
}
}
function SplitArr(Array, Parts) {
let lastIndex = 0
let result = []
function getReamingSum(arr) {
let psum = sumOfArray(Array.slice(lastIndex)) / Parts
console.log('psum ' + psum)
return psum + Parts
}
let psum = getReamingSum(Array)
for (let j = 0; j < Parts; j++) {
let total = 0
for (let i = 0; i < Array.length; i++) {
if (i >= lastIndex) {
total += Array[i]
if (total < psum || j === Parts - 1) {
if (result[j]?.length > 0) {
result[j].push(Array[i])
} else {
let arr = []
arr.push(Array[i])
result[j] = arr
}
lastIndex = i + 1
}
}
}
}
return result
}
let result = SplitArr(Arr, numberOfParts)
console.log(result)
Assuming the array isn't sorted,using a 2D array, with each sub array with sum almost equal to (sum of array / n).
let arr = [9,2,10,4,5,6,7,8,1,3]
arr.sort(function(a, b) { return a - b; });
const sum = arr.reduce((a, b) => a + b, 0);
const n = 2;
const result = [];
let s = 0;
let j = 0;
result[j] = [];
for(let i=0; i<arr.length; i++){
if(s <= Math.floor(sum/n)){
result[j].push(arr[i]);
s +=arr[i];
}
else{
s = 0;
j = j + 1;
result[j] = [];
result[j].push(arr[i]);
}
}
console.log(result)
O/P:
[ [1, 2, 3, 4,5, 6, 7], [ 8, 9, 10 ] ]
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const splitArray = (arr,parts) => {
const totalSum = arr.reduce((acc, item) => {
acc += item;
return acc;
}, 0)
const splitSum = Math.floor(totalSum / parts);
const arrObj = arr.reduce((acc, item,index) => {
acc.sum = acc.sum || 0;
acc.split = acc.split || {};
const pointer = Math.floor(acc.sum / splitSum);
//console.log(item,acc.sum, splitSum, pointer);
acc.split[pointer] = acc.split[pointer] || [];
acc.split[pointer].push(item);
acc.splitSum = splitSum;
acc.sum += item;
return acc;
}, {})
return arrObj;
}
console.log(splitArray(arr,2).split)
You're better off making a custom function:
let currentTotal = 0
let tempList = []
Arr.forEach(val => {
if (val >= 27) {
// push tempList to a new array
tempList = [];
currentTotal = val;
} else {
tempList.push(val);
currentTotal += val;
}
})

How do I build an object counting occurrences in an Array in JavaScript?

I want to count how often a number in an Array occurs. For example, in Python I can use Collections.Counter to create a dictionary of how frequently an item occurs in a list.
This is as far as I've gotten in JavaScript:
var array = [1,4,4,5,5,7];
var obj = {};
for (var i=0; i < array.length; i++) {
/* obj[array[i]] = +=1 */ <= pseudo code
}
How can I create this frequency counter object?
Close but you can't increment undefined so you need to set initial value if it doesn't exist
var array = [1,4,4,5,5,7];
var obj = {};
for (var i=0; i < array.length; i++) {
obj[array[i]] = (obj[array[i]] || 0) +1 ;
}
You were almost there. See below code:
var array = [1,4,4,5,5,7];
var obj = {};
for (var i=0; i < array.length; i++) {
obj[array[i]] = (obj[array[i]] || 0 ) +1;
}
console.log(obj);
Create an object and check if that specific key exist.If exist then increase it's value by 1
var array = [1, 4, 4, 5, 5, 7];
var obj = {};
for (var i = 0; i < array.length; i++) {
if (obj.hasOwnProperty(array[i])) {
obj[array[i]] += 1;
} else {
obj[array[i]] = 1;
}
}
console.log(obj)
You can use the ? : ternary operator to set initial value as 1 and then increment it on subsequent matches.
var array = [1,4,4,5,5,7];
var obj = {};
for (var i=0; i < array.length; i++) {
obj[array[i]] = obj[array[i]]?obj[array[i]]+1:1;
}
console.log(obj);
If the array is always going to be same, and you are going to check frequency of multiple items in the same array without it it being modified, #JohanP's answer is good.
But if you are only going to check frequency of only one item, or the array can change, creating the object is nothing but extra overhead.
In that case, you can do something like this:
const getItemFrequency = function(array, item) {
return array.filter(i => i === item).length;
}
var array = [1,4,4,5,5,7];
console.log(getItemFrequency(array, 4));
Concise logic written as proper function:
function countArrayItemFrequecy(array) {
const length = array.length;
const map = {};
for ( let i = 0; i < length; i++ ) {
let currentItem = array[i];
if (typeof map[currentItem] !== 'undefined' ) {
map[currentItem]++
} else {
map[currentItem] = 1
}
}
return map;
}
You need to make sure to assign default value to your frequency object for the first occurrence of the item. As a shortcut you can use ternary operator
var array = [1,4,4,5,5,7];
var obj = {};
for (var i=0; i < array.length; i++) {
obj[array[i]] = obj[array[i]] ? obj[array[i]]++ : 1;
}
which is the same as:
var array = [1,4,4,5,5,7];
var obj = {};
for (var i=0; i < array.length; i++) {
if (obj[array[i]]) {
obj[array[i]]++;
} else {
obj[array[i]] = 1;
}
}
You can use Object.assign: below clones map and then increments/adds the counter. These are pure (no side effects/param reassignment), single-purpose functions.
addToMap does the same thing as { ...map, map[e]: [e]: (map[e] || 0) + 1 }, but that requires babel.
const addToMap = (map, e) => Object.assign({}, map, { [e]: (map[e] || 0) + 1 });
const buildMap = a => a.reduce(addToMap, {});
Using Array.reduce:
arr.reduce(function (acc, item) {
acc[item] = (acc[item] || 0) + 1;
return acc;
}, {});
Example:
var arr = [1,1,2,4,1,4];
var counts = arr.reduce(function (acc, item) {
acc[item] = (acc[item] || 0) + 1;
return acc;
}, {});
console.log(counts);

Write an algorithm that takes an array and moves all of the zeros to the end

Write an algorithm that takes an array and moves all of the zeros to the end, preserving the order of the other elements.
For example:
moveZeros([false,1,0,1,2,0,1,3,"a"]) // returns[false,1,1,2,1,3,"a",0,0]
My code:
var moveZeros = function (arr) {
var zeros = [];
var others = [];
var res;
var arrayLength = arr.length;
for (var i = 0; i < arrayLength; i++) {
if (arr[i] == 0) {
zeros.push(arr[i]);
} else {
others.push(arr[i]);
}
}
var res = others.concat( zeros );
return res;
}
I get the following result:
Expected: ["a","b",null,"c","d",1,false,1,3,[],1,9,{},9,0,0,0,0,0,0,0,0,0,0],
Instead got: ["a","b",null,"c","d",1,1,3,1,9,{},9,0,0,0,false,0,0,[],0,0,0,0,0]
The expected result is quite close to what I achieved (see above) . I don't understand why I have false in a different place?
try this simply
var arr = [false,1,0,1,2,0,1,3,"a"];
arr.sort(function(a,b){if (a===0){return 1}});
document.body.innerHTML += JSON.stringify(arr);
Try to use a normal for loop and splice at this context to make your job done,
var arr = [false,1,0,1,2,0,1,3,"a"];
for(var i=arr.length;i>0;i--){
if(arr[i] === 0){ arr.push(arr.splice(i,1).pop()); }
}
console.log(arr); //[false, 1, 1, 2, 1, 3, "a", 0, 0]
document.body.innerHTML += JSON.stringify(arr);
Use Array#splice() and Array#push().
function moveZeros(a) {
var i = a.length - 1;
while (i--) {
if (a[i] === 0) {
a.push(a.splice(i, 1)[0]);
}
}
return a;
};
var array = [false, 1, 0, 1, 2, 0, 1, 3, "a"];
document.write('<pre>' + JSON.stringify(moveZeros(array), 0, 4) + '</pre>');
Another approach with swapping items.
function moveZeros(array) {
var length = array.length,
i = length;
while (--i) {
if (array[i] !== 0) continue;
length--;
while (i < length) {
[array[i + 1], array[i]] = [array[i], array[i + 1]];
i++;
}
}
return array;
}
var array = [false, 1, 0, 1, 2, 0, 1, 3, "a"];
console.log(...moveZeros(array));
Please use === operator to compare if value is 0:
if (arr[i] === 0) {
zeros.push(arr[i]);
} else {
others.push(arr[i]);
}
The code snippet below should work , please try , reason for null is that the length of the arr starts count from zero so when using <= you should subtract 1 from the total length.
var moveZeros = function (arr) {
// TODO: Program me
let zero = []
let others = []
let together = []
for (let i =0; i <= arr.length-1; i++){
if (arr[i] === 0){
zero.push(arr[i])
}
else{
others.push(arr[i])
}
}
together = others.concat(zero)
return together
}
var titleCase = function(title) {
var arr = [];
for (i = 0; i < title.length ; i++) {
if (title[i] !== 0 ) {
arr.push(title[i]);
}
}
for (i = 0 ; i < title.length ; i++) {
if (title[i] == 0 ) {
arr.push(title[i]);
}
}
return arr;
}
You could use the filter() method to achieve your goal. With the arrow notation you can shorten the code. For example: arr => arr === 0 is the shorthand for the anonymous filter function function(arr) { return arr === 0; }
var moveZeros = function (arr) {
const zeros = arr.filter (arr => arr === 0);
const others = arr.filter (arr => arr !== 0);
return others.concat(zeros);
}
var arr = [false,1,0,1,2,0,1,3,"a"]
function moveZeros(arr){
var zeros = [];
var others = [];
var output;
for (var i=0; i< arr.length; i++){
if (arr[i]===0){
zeros.push(arr[i]);
}else{
others.push(arr[i])
}
}
output = others.concat(zeros);
console.log(output);
}
moveZeros([false,1,0,1,2,0,1,3,"a"]);

How to get subset of two arrays into a different array using javascript?

i have 2 arrays.
arr1=[1,8,1,3,2]
arr2=[3,8,1]
I want to put elements [8,1] subset into arr3. How can i do this using javascript?I used the following code. But doesn't seemed to be working.
function subsetFind() {
var arr1 = [1,8,1,3,2]
var arr2 = [3,8,1]
var arr3 = [];
var arr1length = arr1.length;
var arra2length = arr2.length;
for(var i = 0; i < arr1length; ++i){
for(var j=0;j<arra2length;j++) {
if(arr1[i] != arr2[j]) {
break;
} else {
arr3.push(arr1[i]);
break;
}
}
}
alert(arr3);
}
Try this solution - it checks whether both current and previous OR current and next value is equal:
function subsetFind() {
var arr1 = [1,8,1,3,2]
var arr2 = [3,8,1]
var arr3 = [];
var arr1length = arr1.length;
var arra2length = arr2.length;
var used_i = 0;
for(var i = 0; i < arr1length; ++i){
if(used_i != 0 && used_i < i-1){
break;
}
for(var j=0;j<arra2length;j++) {
if((arr1[i] == arr2[j] && arr1[i-1] == arr2[j-1]) || (arr1[i] == arr2[j] && arr1[i+1] == arr2[j+1])) {
arr3.push(arr1[i]);
used_i = i;
}
}
}
alert(arr3);
}
Output:
8,1
I hope that you want; (renewed :)
function subset() {
var arr1 = [1, 9, 3, 5, 4, 8, 2, 6, 3, 4]
var arr2 = [5, 2, 4, 8, 2, 6, 4]
var arr3 = [];
var minSize=2; // minimum 2 element must in intersection
var findedMax = "";
var arr1Joined = ""; arr1.forEach(function (a) { arr1Joined += "," + a; });
for(k=minSize;k<arr2.length;k++)
arr2.forEach(function (x,y) {
var fkey="";
for (i = y; i <= y+k; i++)
fkey += "," + arr2[i];
if (arr1Joined.indexOf(fkey) >= 0) findedMax = fkey;
});
arr3=findedMax.substr(1).split(",");
alert(arr3);
}
Try This Out:
Reference n-dru's answer:
function subset () {
var arr1 = [1,9,3,5,4,8,2,6,3,4]
var arr2 = [5,2,4,8,2,6,4]
var arr3 = [];
var arr1length = arr1.length;
var arra2length = arr2.length;
var finalResult;
for(var i = 0; i < arr1length; ++i){
for(var j=0;j<arra2length;j++) {
if((arr1[i] == arr2[j] && arr1[i-1] == arr2[j-1]) || (arr1[i] == arr2[j] && arr1[i+1] == arr2[j+1])) {
arr3.push(arr1[i]);
}
else
{
finalResult = arr3.toString();
}
}
}
alert(finalResult);
}
DEMO
I believe Your question was alredy answerd in: Simplest code for array intersection in javascript and Finding matches between multiple JavaScript Arrays . You can also look into implementation of _.intersection in lowdash library.
ES6 way.
[...new Set(arr1)].filter(v => arr2.includes(v))
Break down:
new Set(arr1) // convert arr1 to Set to remove duplicates
[...new Set(arr1)] // convert back to array
arr2.includes(v) // test if arr2 includes `v`
[...new Set(arr1)].filter(v => arr2.includes(v)) // choose unique elements in both arrays

Comparing and Filtering two arrays

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));

Categories

Resources