how to make _.includes method - javascript

I am a junior developer who has been coding for 4 weeks.
I'm working on a JavaScript method.
I'll show you the code I used first.
_.each = function (collection, iteratee) {
if(Array.isArray(collection)===true){
for(let i=0;i<collection.length;i++){
iteratee(collection[i],i,collection)
}
}else{
let objvalues= Object.values(collection)
let objkeys = Object.keys(collection)
for(let i=0;i<objvalues.length;i++){
iteratee(objvalues[i],objkeys[i],collection)
}
}
};
_.includes = function (arr, target) {
let result
_.each(arr, function(a){
if(a === target)
result = true
if (a !== target)
result = false
})
return result;
};
It's a condition.
If the _.include method matches the value found by the element in the array, the true must be returned.
If the element in the array does not match the value you are looking for, you must return false.
I made the _include method.
If the element in the array does not match the value you are looking for, the return to false is successful.ten thousand
If the element in the array matches the value you are looking for, you must return true
This is where you fail.
It seems that the ture cannot be returned and only false is returned.
How should I handle this?

The problem is here:
_.each(arr, function(a){
if(a === target)
result = true
if (a !== target)
result = false
})
You reassign result on every iteration. As a result, the only iteration that matters for the final value of result is the last iteration.
Instead, initialize result to false, and reassign to true when the target is found:
const _ = {};
_.each = function(collection, iteratee) {
if (Array.isArray(collection) === true) {
for (let i = 0; i < collection.length; i++) {
iteratee(collection[i], i, collection)
}
} else {
let objvalues = Object.values(collection)
let objkeys = Object.keys(collection)
for (let i = 0; i < objvalues.length; i++) {
iteratee(objvalues[i], objkeys[i], collection)
}
}
};
_.includes = function(arr, target) {
let result = false;
_.each(arr, function(a) {
if (a === target)
result = true
})
return result;
};
console.log(
_.includes([1, 2, 3], 2)
);
It'd be cleaner to break the loop once a match is found, but your _each isn't set up for that:
const _ = {};
_.each = function(collection, iteratee) {
if (Array.isArray(collection) === true) {
for (let i = 0; i < collection.length; i++) {
iteratee(collection[i], i, collection)
}
} else {
let objvalues = Object.values(collection)
let objkeys = Object.keys(collection)
for (let i = 0; i < objvalues.length; i++) {
iteratee(objvalues[i], objkeys[i], collection)
}
}
};
_.includes = function(arr, target) {
for (const a of arr) {
if (a === target)
return true
}
return false;
};
console.log(
_.includes([1, 2, 3], 2)
);

In addition to what CertainPerfomance already said, you could see how Array.includes was implemented to get an inspiration, here is the specifications from TC39.

Related

I am trying to write a js function that returns the index of a an array of strings, in case the string "keys" is in the array

My function should return the index where "keys" is located, in case of success, or -1 if "keys" is not in the array. But I get -1, I donĀ“t see where is my mistake.
const findMyKeys = arr => {
for (let i = 0; i < arr.length; i++) {
if (arr[i] === 'keys') {
return i;
} else {
return -1;
}
}
}
const randomStuff = ['credit card', 'screwdriver', 'keys']
You can do it by using findIndex.
const findMyKeys = arr => arr.findIndex(item => item === 'keys');
console.log(findMyKeys(['credit card', 'hello world', 'keys']));
console.log(findMyKeys(['credit card', 'hello world']));
You should only return -1 if the for loop finishes and did not find the string:
const findMyKeys = (arr) => {
for (let i = 0; i < arr.length; i++) {
if (arr[i] === 'keys') {
return i;
}
}
return -1;
}
const randomStuff = ['credit card', 'screwdriver', 'keys']
console.log(findMyKeys(randomStuff))
randomStuff.pop();
console.log(findMyKeys(randomStuff))
You can use the .indexOf() method for this:
const findMyKeys = arr => {
return arr.indexOf("keys")
}
const randomStuff = ['credit card', 'screwdriver', 'keys']
const result = findMyKeys(randomStuff)
console.log(result)
You could try arrays findIndex method.
['a', 'b', 'c'].findIndex((item, index) => item === 'c')
The findIndex() method returns the index of the first element in the array that satisfies the provided testing function. Otherwise, it returns -1, indicating that no element passed the test.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex

how to print a unique number in a array

The problem is to find the unique number in a array such as [2,2,2,5].
The output should be 5 as it is the 1 unique element in the array.
I have attempted this:
function findUniq(arr) {
var b= arr[0];
var c;
for(var i=0; i<arr.length; i++)
{
if(arr[i]===b )
{
b=arr[i]
}
else
{
c=arr[i];
}
}
return c
console.log(findUniq([3, 5, 3, 3, 3]))
This works fine unless the unique number is the first element in the array. How do I fix this?
You can use indexOf and lastIndexOf to see if a value occurs more than once in the array (if it does, they will be different), and if so, it is not the unique value. Use filter to process the array:
let array = [2,2,2,5];
console.log(array.filter(v => array.indexOf(v) === array.lastIndexOf(v)));
array = [5,3,3,3,3];
console.log(array.filter(v => array.indexOf(v) === array.lastIndexOf(v)));
array = [4,4,5,4];
console.log(array.filter(v => array.indexOf(v) === array.lastIndexOf(v)));
You can create a recursive function that will take the first element of the array and see if it exists in the rest of it, if it does, it will take the next element and do the same, return the element if it doesn't exist in the rest of the array :
const arr = [3, 3, 3, 5, 3];
const find = arr => {
const [f, ...rest] = arr;
if(rest.includes(f))
return find(rest);
else
return f;
}
const result = find(arr);
console.log(result);
Note that this will return the last element if all of them are the same [3,3,3] will return 3
Try something like this using a set, which only stores unique elements:
var set = new Set(arr);
// count instances of each element in set
result = {};
for(var i = 0; i < a.length; ++i) {
if(!result[arr[i]])
result[arr[i]] = 0;
++result[arr[i]];
}
for (var value in result) {
if (value == 1) {
return value;
}
}
// if there isn't any
return false;
This should work, please tell me if it doesn't.
This is another implementation that is surely less efficient than that of #Nick's, but it is a valid algorithm anyway:
function findUniq(arr) {
var elemCount = new Map();
var uniq = [];
// Initialize elements conts
for (var k of arr.values()) {
elemCount.set(k, 0);
}
// Count elements
for (var k of arr.values()) {
elemCount.set(k, elemCount.get(k) + 1);
}
// Add uniq elements to array
for (var [k, v] of elemCount.entries()) {
if (v === 1) uniq.push(k);
}
return uniq;
}
console.log(findUniq([3, 5, 3, 3, 3]))
if you prefer .reduce over .map for your use case (for performance/etc. reasons):
function existance(data) {
return data.reduce((a, c) => (data.indexOf(c) === data.lastIndexOf(c)) ? a.concat(c) : a, []);
}
console.log(existance([1,1,1,2]));
console.log(existance([1,1,2,3,4,5,5,6,6,6]));

How to search for a string in array of arrays using javascript function

This function is able to search for a string in an array:
public checkElement( array ) {
for(var i = 0 ; i< array.length; i++) {
if( array[i] == 'some_string' ) {
return true;
}
}
}
How can i use array of arrays in the for loop? I want to pass this to a function that search a string with if condition.
Example input:
array[['one','two'],['three','four'],['five','six']].
You can try the "find" method instead
let arr = [['one','two'],['three','four'],['five','six']];
function searchInMultiDim(str) {
return arr.find(t => { return t.find(i => i === str)}) && true;
}
searchInMultiDim('one');
This is a recursive solution that checks if an item is an array, and if it is searches it for the string. It can handle multiple levels of nested arrays.
function checkElement(array, str) {
var item;
for (var i = 0; i < array.length; i++) {
item = array[i];
if (item === str || Array.isArray(item) && checkElement(item, str)) {
return true;
}
}
return false;
}
var arr = [['one','two'],['three','four'],['five','six']];
console.log(checkElement(arr, 'four')); // true
console.log(checkElement(arr, 'seven')); // false
And the same idea using Array.find():
const checkElement = (array, str) =>
!!array.find((item) =>
Array.isArray(item) ? checkElement(item, str) : item === str
);
const arr = [['one','two'],['three','four'],['five','six']];
console.log(checkElement(arr, 'four')); // true
console.log(checkElement(arr, 'seven')); // false
Try this code:
function checkElement(array){
for(value of array){
if(value.includes("some string")){return true}
}
return false
}
console.log(checkElement([["one","two"],["three","four"],["five","six"]]))
console.log(checkElement([["one","two"],["three","four"],["five","some string"]]))

Turning for loop into forEach JavaScript

Working on a function that verifies if each number in an array is true or false and returns the first true number.
Have a working solution with a for loop as follows:
function findElement(arr, func) {
var num;
for (var a = 0; a < arr.length; a++) {
if (func(arr[a])) {
num = arr[a];
return num;
}
}
return num;
}
findElement([1, 3, 5, 8, 9, 10], function(num) {
return num % 2 === 0;
})
// Should return 8
But I'm trying (in order to get my head around forEach better) to convert it into a forEach loop.
This is where I am so far, but I don't see how to actually return the num out of the loop after it's been established that the function result is true:
function findElement(arr, func) {
if (arr.forEach(func) === true) {
return num;
}
}
findElement([1, 2, 3, 4], num => num % 2 === 0);
Not sure how to use forEach but you could use array.prototype.filter:
function findElement(arr, func) {
return arr.filter(func)[0];
}
#cdhowie suggested the use array.prototype.find in order to need the usage of [0].
function findElement(arr, func) {
return arr.find(func);
}
Obviously, that is just a guess because it may raise an error if no item in the array meets the requirements of func.
If you still are looking about use forEach maybe you could do something like this:
function findElement(arr, func) {
matches = []
arr.forEach((item) => {
if (func(item)) {
matches.push(item)
}
});
return matches[0];
}
Or:
function findElement(arr, func) {
match = null
arr.forEach((item) => {
match = (match == null && func(item)) ? item : match
});
return match;
}
Again, you will have to check how to handle the error if no item in the array meets the requirements f your func.
Any of both codes produce
console.log(findElement([1, 3, 5, 8, 9, 10], function(num) { return num % 2 === 0; })))
8
function findElement(arr, func) {
var num;
arr.forEach(function(element) {
if (!num && func(element)) {
num = element;
}
});
return num;
}
For more options you can check this question: how to stop Javascript forEach?
As has already been mentioned, this is not how forEach should be used.
However, you can still get the behavior you want:
function findElement(arr, func) {
var num;
arr.forEach(item =>{
if (func(item)) {
num = item;
// .forEach does not have an early return
// but you can force it to skip elements by removing them
while (true) {
// Remove all elements
var removedItem = arr.shift();
if (removedItem === undefined) {
// All elements removed
break;
}
}
}
return num;
}
This is even mentioned in the documentation
maybe like this
function findElement(arr, func) {
var num = null;
for (var a = 0; a < arr.length && num === null; a++) {
var val = arr[a];
num = func(val) ? val : null;
}
return num;
}
console.log(findElement([1, 3, 5, 8, 9, 10], function(num) {
return num % 2 === 0;
}));
here is your findElement method with foreach
function findElement(arr, func) {
var num = 0;
arr.forEach(function(item){
if (func(item))
return item;
})
return num;
}

counting duplicate arrays within an array in javascript

I have an array of arrays as follows:
[[3, 4], [1, 2], [3, 4]]
I wish to create a new array of arrays that has no duplicates, and has a count of the number of occurrences of each element in the first array:
[[3,4,2], [1,2,1]]
here is what I have so far:
var alreadyAdded = 0;
dataset.forEach(function(data) {
From = data[0];
To = data[1];
index = 0;
newDataSet.forEach(function(newdata) {
newFrom = newData[0];
newTo = newData[1];
// check if the point we are looking for is already added to the new array
if ((From == newFrom) && (To == newTo)) {
// if it is, increment the count for that pair
var count = newData[2];
var newCount = count + 1;
newDataSet[index] = [newFrom, newTo, newCount];
test = "reached here";
alreadyAdded = 1;
}
index++;
});
// the pair was not already added to the new dataset, add it
if (alreadyAdded == 0) {
newDataSet.push([From, To, 1]);
}
// reset alreadyAdded variable
alreadyAdded = 0;
});
I am very new to Javascript, can someone help explain to me what I'm doing wrong? I'm sure there is a more concise way of doing this, however I wasn't able to find an example in javascript that dealt with duplicate array of arrays.
Depending on how large the dataset is that you're iterating over I'd be cautious of looping over it so many times. You can avoid having to do that by creating an 'index' for each element in the original dataset and then using it to reference the elements in your grouping. This is the approach that I took when I solved the problem. You can see it here on jsfiddle. I used Array.prototype.reduce to create an object literal which contained the grouping of elements from the original dataset. Then I iterated over it's keys to create the final grouping.
var dataSet = [[3,4], [1,2], [3,4]],
grouping = [],
counts,
keys,
current;
counts = dataSet.reduce(function(acc, elem) {
var key = elem[0] + ':' + elem[1];
if (!acc.hasOwnProperty(key)) {
acc[key] = {elem: elem, count: 0}
}
acc[key].count += 1;
return acc;
}, {});
keys = Object.keys(counts);
for (var i = 0, l = keys.length; i < l; i++) {
current = counts[keys[i]];
current.elem.push(current.count);
grouping.push(current.elem);
}
console.log(grouping);
Assuming order of sub array items matters, assuming that your sub arrays could be of variable length and could contain items other than numbers, here is a fairly generic way to approach the problem. Requires ECMA5 compatibility as it stands, but would not be hard to make it work on ECMA3.
Javascript
// Create shortcuts for prototype methods
var toClass = Object.prototype.toString.call.bind(Object.prototype.toString),
aSlice = Array.prototype.slice.call.bind(Array.prototype.slice);
// A generic deepEqual defined by commonjs
// http://wiki.commonjs.org/wiki/Unit_Testing/1.0
function deepEqual(a, b) {
if (a === b) {
return true;
}
if (toClass(a) === '[object Date]' && toClass(b) === '[object Date]') {
return a.getTime() === b.getTime();
}
if (toClass(a) === '[object RegExp]' && toClass(b) === '[object RegExp]') {
return a.toString() === b.toString();
}
if (a && typeof a !== 'object' && b && typeof b !== 'object') {
return a == b;
}
if (a.prototype !== b.prototype) {
return false;
}
if (toClass(a) === '[object Arguments]') {
if (toClass(b) !== '[object Arguments]') {
return false;
}
return deepEqual(aSlice(a), aSlice(b));
}
var ka,
kb,
length,
index,
it;
try {
ka = Object.keys(a);
kb = Object.keys(b);
} catch (eDE) {
return false;
}
length = ka.length;
if (length !== kb.length) {
if (Array.isArray(a) && Array.isArray(b)) {
if (a.length !== b.length) {
return false;
}
} else {
return false;
}
} else {
ka.sort();
kb.sort();
for (index = 0; index < length; index += 1) {
if (ka[index] !== kb[index]) {
return false;
}
}
}
for (index = 0; index < length; index += 1) {
it = ka[index];
if (!deepEqual(a[it], b[it])) {
return false;
}
}
return true;
};
// Recursive function for counting arrays as specified
// a must be an array of arrays
// dupsArray is used to keep count when recursing
function countDups(a, dupsArray) {
dupsArray = Array.isArray(dupsArray) ? dupsArray : [];
var copy,
current,
count;
if (a.length) {
copy = a.slice();
current = copy.pop();
count = 1;
copy = copy.filter(function (item) {
var isEqual = deepEqual(current, item);
if (isEqual) {
count += 1;
}
return !isEqual;
});
current.push(count);
dupsArray.push(current);
if (copy.length) {
countDups(copy, dupsArray);
}
}
return dupsArray;
}
var x = [
[3, 4],
[1, 2],
[3, 4]
];
console.log(JSON.stringify(countDups(x)));
Output
[[3,4,2],[1,2,1]]
on jsFiddle
After fixing a typo I tried your solution in the debugger; it works!
Fixed the inner forEach-loop variable name to match case. Also some var-keywords added.
var alreadyAdded = 0;
dataset.forEach(function (data) {
var From = data[0];
var To = data[1];
var index = 0;
newDataSet.forEach(function (newData) {
var newFrom = newData[0];
var newTo = newData[1];
// check if the point we are looking for is already added to the new array
if ((From == newFrom) && (To == newTo)) {
// if it is, increment the count for that pair
var count = newData[2];
var newCount = count + 1;
newDataSet[index] = [newFrom, newTo, newCount];
test = "reached here";
alreadyAdded = 1;
}
index++;
});
// the pair was not already added to the new dataset, add it
if (alreadyAdded == 0) {
newDataSet.push([From, To, 1]);
}
// reset alreadyAdded variable
alreadyAdded = 0;
});
const x = [[3, 4], [1, 2], [3, 4]];
const with_duplicate_count = [
...x
.map(JSON.stringify)
.reduce( (acc, v) => acc.set(v, (acc.get(v) || 0) + 1), new Map() )
.entries()
].map(([k, v]) => JSON.parse(k).concat(v));
console.log(with_duplicate_count);

Categories