Symmetrical Difference (Understanding the scope of this function) - javascript

I was completing a task of FCC which was to get the symmetrical difference of a varied number of arrays. Part of the reason I got stuck was because of my placement of the results array where I would push the unique elements to.I had it outside the function makeSym and I needed to have it inside which i discovered when checking out the hints page. But I dont know why.
function sym() {
var results = []; // I had the results array here rather than inside function makeSym
var allArrays = [];
for (var i = 0; i < arguments.length; i++) {
allArrays.push(arguments[i]);
}
function makeSym(arrOne, arrTwo) {
// when the results array was placed here, it worked
arrOne.forEach(function (a) {
if (arrTwo.indexOf(a) === -1 && results.indexOf(a) === -1) {
results.push(a);
}
});
arrTwo.forEach(function (a) {
if (arrOne.indexOf(a) === -1 && results.indexOf(a) === -1) {
results.push(a);
}
});
return results;
}
return allArrays.reduce(makeSym);
}
sym([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5]);
My question is why does this change my result, why don't I get the correct symmetrical difference. What is happening in the mechanics that I was missing.
the difference between these two placements was a return of 1,4,5 and a result of 1,3,4,5 (the correct answer should be 1,4,5)
I am assuming this has something to do with scope and closure and this is something I really want to understand more, any information would be helpful.
The second part of my question for anyone still with me, is why does the reduce work in this, what is the reduce doing. I understand its reducing to a single array my multiple arrays but how come the function makeSym doesnt do this alone, in my mind I should be able to execute the function with allArrays as a parameter then return results and complete the challenge this way, but this doesnt work and the reason why it doesnt work isnt obvious to me at all. Again any elucidation would help me understand this more and move forward. Cheers

Related

Finding an item's index in an array

I was writing a function that takes two arguments, an array and a number, and returns the index of the number if it's present in the array. The issue I encounter is the fact that my code returns properly without the "else" part, however, when I add the code about returning "-1" it doesn't work properly and it seems as if the compiler only takes "return -1" into account, no matter what arguments I use. Could anyone help me solve this issue?
function search(arr, item) {
for(let i=0; i<arr.length; i++){
if(item===arr[i]){
return i;
}else if(item!==arr[i]){
return -1;
}
}
}
It's always giving me an output of "-1", when it's supposed to give the index of the "item" argument if it's presents in the first array argument.
You need return -1 outside the loop so it only returns -1 if it makes it all the way through the loop without finding something. If it finds something before that, it will return the index:
function search(arr, item) {
for(let i=0; i<arr.length; i++){
if(item===arr[i]){
return i;
}
}
return -1;
}
console.log(search([1, 2, 3], 5))
console.log(search([1, 2, 3], 2))
Think about this sequentially.
Let's say your array is [1, 2, 3] and you're looking for 3.
The function loops over the array. The first value considered is 1. That actives the else block and returns -1 before the other values are even considered. Remember return means end of function execution.
In any case, you can greatly simplify the function:
return arr.indexOf(item);

Best way to filter for duplicates? [duplicate]

This question already has answers here:
Get all unique values in a JavaScript array (remove duplicates)
(91 answers)
Closed 4 years ago.
I posted about this before trying to use a regular expression, but this time is a bit different.
So I have this list of 500 phone numbers. Here is a little sample of them:
{
8664665844
8885444636
8664604776
8776434327
8887441938
8882642882
8888097429
8668943258
8777711234
8669894327
}
It looks a bit different, this is on my mongoDB server, so its more like an array of objects with a unique uid... so for example:
[
{
_id: kasjf234lkj109euf9023u4n,
field1: 8669894327,
}
]
something like that right.
So basically, my webapp is using a csv file of numbers that you want to compare to your base numbers.
My first thought was using a for, while, for loop kind of thing but im not sure how well it'll work:
for(var i = 0; i < basenums.length; i++){
while ( i >= 0 ){
for(var j = 0; j < comparing.length; j++){
if comparing[j] == basenums.field1[i]{
push that number to a 'dupes' array
}else{
break or something?
}
}
}
}
...this logic is starting to hurt my head...
I know theres an 'includes()' method, but I havn't really used it and when I tried it in this case, It gave me everything as false, even tho the list I was using to compare is just a copy of my 'basenums' list on my server.
What would be the more 'correct' way of doing this?
I'm trying to compare an array with an array. Not a value in its specific array to its own array.
So, rather than marking this as a duplicate, maybe you should re-read:
I have 2 arrays of numbers: [1, 2, 3, 4, 5, 6] and [1, 2, 3, 4, 5, 6] How do I take array a index 0 and compare it to array b every index, then take index 1 of array a and compare to every index in array b, so on and so forth until i > arrayA.length.
Don't try to do everything in one single step. Break your problem into smaller chunks:
Format mongo's response into a hash map that you can efficiently query (O(1))
Test each input number against this map
Step 1:
var hashmap = {}
basenums.forEach(function(basenum) {
hashmap[basenum.field1] = true;
})
Step 2:
var dupes = [];
comparing.forEach(function(comparingNum) {
if(hashmap[comparingNum]) {
dupes.push(comparingNum);
}
})
EDIT: I am not sure, whether you want to have your dupes as a set (unique array). If so, you could use an alternate Step 2:
var dupesMap = {};
comparing.forEach(function(comparingNum) {
if(hashmap[comparingNum]) {
dupesMap[comparingNum] = true;
}
})
var dupes = Object.keys(dupesMap);
You can push values into an array and create a new set with the array. Sets do not keep redundant elements in them. Try this;
let a = ["a","b","a","b","a","b","a","b","a","c"];
console.log(a);
let uniqueA = [...new Set(a)];
console.log(uniqueA);
By the way, for piece of code I got a help from this page: https://medium.com/front-end-hacking/getting-unique-values-in-javascript-arrays-17063080f836

Iterating through a function call

After years of writing loops in C++ the tedious way
for(int i=0; i<N; ++i) {
...
}
it becomes quite nice to use iterators
for(it i=v.begin(); i<v.end(); ++i) {
...
}
and ultimately moving to range iterators
for(auto i:v) {
...
}
In JavaScript also the for can be used, in a style nearly identical
(minus the type declaration and the pre/post increment operator) to
the first one above.
Still, in all of these the for is there. The D3.js
library demonstrates an alternative. One can iterate over an array by writing
d3.select("body")
.selectAll("p")
.data([4, 8, 15, 16, 23, 42])
.enter().append("p")
.text(function(d) { return "Iā€™m number " + d + "!"; });
Here the enter mutates to a for loop. The documentation
explains nicely the client-side view of joins. What I am missing is a
standalone example of the (functional programming?) style of
converting a function call to an iteration.
No doubt this is not unique to D3.js. This is just where I encountered the idiom.
Can you suggest a few lines of standalone JavaScript code that
demonstrate iteration through a function call?
There are at least a couple of built-in functions that come to my mind.
map()
This one is very obvious.
[1, 2, 3]
.map(someNumber => someNumber * someNumber)
.map((powered, index) => index + "::" + powered);
// --> [ "1::1", "2::4", "3::9" ]
Chains well, right? Takes some input and produces the result consisting of elements calculated by applying a function element-wise.
Recommendation: try to use with pure functions whenever possible (produce the same results for same inputs, don't mutate the original collection if possible, nor produce any side effects).
forEach()
This function iterates through all elements of an array too, and applies a function, without returning anything back. Therefore, it can only end a chain of calls, but cannot be used for further chaining.
[1, 2, 3, 4]
.forEach(number => console.info(number));
Recommendation: forEach() is useful when we want to write some code that will result in a side effect per entry in the collection being iterated.
filter()
Filter function uses a predicate is used to sift the wheat from the chaff. The predicate is defining a criteria for the items you want to deal with on the next "stage".
[null, undefined, 0, 1, 2, 3, NaN, "", "You get the idea"]
.filter(Boolean)
.map(filteredElement => filteredElement + "!")
// --> [ "1!", "2!", "3!", "You get the idea!" ]
Recommendation: try to use with pure functions whenever possible. I.e. don't do anything else in filter other than things immediately related to filtration logic itself.
Object.keys() and Object.entries()
These two functions are helpful when we need to iterate over object's keys or key-value pairs, rather than an array's elements.
const targetObject = { a: 1, b: 2, c: 3 };
Object
.keys(targetObject)
.map(key => key + "=" + targetObject[key])
// --> [ "a=1", "b=2", "c=3" ]
same result can be achieved like this
Object
.entries({ a: 1, b: 2, c: 3 })
.map((key, value) => key + "=" + value)
// --> [ "a=1", "b=2", "c=3" ]
Recommendation: you may want to use Object.hasOwnProperty(...) when using working with Object.keys(...). See the documentation for details.
find()
The one is almost trivial. Let's us search for an item that matches a predicate. The search is "left-to-right", and it stops whenever the first "match" is found.
[1, 5, 10, 15]
.find(number >= 7)
// --> 10
findIndex() function can be used when we're looking for a position of an element that matches a predicate.
some() and every()
These functions check whether
a) there is at least one element matching a predicate; or
b) each and every element is matching a predicate.
const arrayOfNumbers = [2, 4, 6, 8, 10];
arrayOfNumbers.every(number => number % 2 === 0); // --> true
arrayOfNumbers.every(number => number % 2 === 1); // --> false
arrayOfNumbers.some(number => number > 1); // --> true
arrayOfNumbers.some(number => number <= 1); // --> false
reduce() and `reduceRight()`
The last one to mention in this quick review is the function that takes a list of things and aggregates it into a single result.
[-1, 0, 1, 2, 3]
.filter(value => value >= 0) // [0, 1, 2, 3]
.map(value => value + 1) // [1, 2, 3, 4]
.reduce((subTotal, currentValue) => subTotal + currentValue, 5);
// --> 15
Recommendation: try to use with pure functions whenever possible.
Universally applicable note on performance. In my benchmarks (don't have them on hand), a hand-written for loop was always faster than forEach, map, and other iterating functions. I do still prefer the functions unless the performance is being severely affected. There two main reasons for that: 1) easier to avoid off-by-one-errors; 2) the code is more readable, since each single function defines an independent step in the data processing flow, thus making code simpler and more maintainable.
I hope, this is an okay overview of some built-in chain-able JavaScript functions. More are described here. Take a look at concat(), sort(), fill(), join(), slice(), reverse() -- I frequently use them too.
If you need something like first() or last(), you will not find them in native functions. Either write your own ones, or use third-party libraries (e.g. lodash, rambda.js).
Here is an example implementation of Array.prototype.forEach:
function foreach(array, cb) {
for (var i = 0; i < array.length; ++i)
cb(array[i], i, array);
}
foreach([2,8,739,9,0], (n, i) =>
console.log("number: %s\nindex: %s\n", n, i));
surely I don't have to spoonfeed you do I?
function array_iterator(array) {
var i = 0;
function next() {
return array[i++];
}
function head() {
return array[i];
}
function tail() {
return array[array.length-1];
}
function more() {
return i < array.length;
}
function done() {
return !more();
}
function reset() {
i = 0;
}
return { next, head, tail, done, more, reset };
}
var nums = [3,34,4];
var iter = array_iterator(nums);
while (iter.more()) {
console.log(iter.next());
}

Reversing an array - Eloquent javascript chapter 4

I am trying to work through this problem and I am having trouble understanding why the function reverseArrayInPlace isn't doing what I want it to. The console.log in the function will return a reversed array, but when I return the same thing, I don't get the reversed array.
I am a beginner so please dumb down the answers alot. Thanks
function reverseArray(array){
var x = [];
for (i=array.length - 1; i>=0; i--){
x.push(array[i]);
}
return x;
}
function reverseArrayInPlace(array){
console.log(reverseArray(array));
return reverseArray(array);
}
//console.log(reverseArray(["A", "B", "C"]));
// ā†’ ["C", "B", "A"];
var arrayValue = [1, 2, 3, 4, 5];
reverseArrayInPlace(arrayValue);
console.log(arrayValue);
// ā†’ [5, 4, 3, 2, 1]
Edit: Thanks for the replies. Can I get some feedback on this function:
function reverseArrayInPlace(array){
for (i=1; i<array.length; i++){
var x = array[i];
array.splice(i,1);
array.unshift(x);
}
return array;
}
It seems to be working for me. Can you see anything wrong with it?
You aren't reversing the array in place
In the function you are creating a new array and then adding the elements in reverse order
in the first line of your function you create a new variable
var x = [];
Unless you want to change your implementation to handle both cases in reverseArray you need to implement a different solution in the reverseArrayInPlace function
You will need to
Determine the element to swap from the front
Determine the element to swap from the back
Know when you have reached the middle of the array and stop
You can optionally return the array if you would like to, but since the change is made in place you shouldn't need to
The reverseArrayInPlace() function isn't actually working in place. It is calling reverseArray() which is creating a new array to store the elements. As such, it needs to be returning this value.
why not just...
var arrayValue = [1, 2, 3, 4, 5];
arrayValue = arrayValue.reverse();
console.log(arrayValue);
edit: nvm i see you are workign through a tutorial. imo this is the most elegant way though.

Can someone explain why this does not work?

I'm going through the interview cake algorithms. This is basically self-assigned homework. I've given it a few goes, and my solution is fairly ugly, but I don't understand why it's not giving me the correct output. Only one loop executes in the algorithm, and I've tried switching the order, as well as other versions along this line.
I'm a little stuck here, and have two questions relating to this algorithm, which I'm trying to complete in straight-up Javascript.
Here's the problem:
You have an array of integers, and for each index you want to find the product of every integer except the integer at that index. Write a function get_products_of_all_ints_except_at_index() that takes an array of integers and returns an array of the products. Do not use division.
The array [1, 7, 3, 4]
Would return:
[84, 12, 28, 21]
By calculating:
[7*3*4, 1*3*4, 1*7*4, 1*7*3]
My overwrought attempt is below:
var l = [84, 12, 28, 21],
products_before_curr_index = 1,
products_after_curr_index = 1,
backwards_index=1,
forwards_index,
product_array = [];
for(var factor=0; factor<l.length; factor++){
forwards_index=factor+1;
while(forwards_index<l.length){
products_after_curr_index*=l[forwards_index];
forwards_index+=1;
}
if(factor>0){
products_before_curr_index *= l[factor-backwards_index];
backwards_index+=1;
}
product_array.push(products_after_curr_index*products_before_curr_index);
backwards_index=1;
products_after_curr_index = 1;
products_before_curr_index=1;
}
This returns [84, 12, 28, 3]
My questions:
Why doesn't this work? Where am I going wrong?
There must be a more elegant way to do this using slice or map. I'm stumped. Can someone give me a hint here?
This one uses map and reduce methods of Array object.
function get_products_of_all_ints_except_at_index(inList) {
var product = function (x, y) { return x * y; };
var lists = inList.map(function (v, i, a) {
return a.slice(0, i).concat(a.slice(i + 1, a.length));
});
return lists.map(function (v, i, a) { return v.reduce(product); });
}
// test case
console.log(get_products_of_all_ints_except_at_index([1, 7, 3, 4]));
Yeah it looks like you have overcomplicated it a bit. The problem description gives you a bit of a hint on how to solve the problem. For each integer in the array, you want to find the product of all the other integers. In other words, you can loop over each item in the array, then loop over each item in the array again (aka, a nested loop) and add up all the products except for the current index of the first array.
For example:
var a = [1, 7, 3, 4];
var b = [];
a.forEach(function( value_1 ) {
var product = 1;
a.forEach(function( value_2 ) {
if ( value_1 != value_2 )
product *= value_2;
});
b.push( product );
});
console.log( b ); // [84, 12, 28, 21]
Your original solution doesn't work because you only ever go back once. You use a while loop to go forward through the entire array to calculate the product of all the elements after, but you only use one single calculation to go backwards:
products_before_curr_index *= l[factor-backwards_index];
So you're only ever getting the product of the value immediately before the current index. You never go back further. If you're wondering, you only happen to get the third value (28) right because the first number is 1 (aka, multiplying by 1 wouldn't have done anything anyway). Try changing that first number to anything that isn't 1 and you'll see that the third calculation also fails.
I didn't particularly liked the solution given by Interview Cake, I felt it was complicated. I may not have the most optimized solution, and I used Numpy which is not clear if we can (but it doesn't say we can't, so...)
It worked for all test cases and I feel it's way more simple/easy to grasp:
` import numpy as np
def get_products_of_all_ints_except_at_index(int_list):
if len(int_list) < 2:
raise IndexError("you need two numbers at least")
products = []
for i in range(len(int_list)):
temp_list = int_list.copy()
del temp_list[i]
prod = np.prod(temp_list)
products.append(prod)
return products

Categories

Resources