javascript find symmetric difference - javascript

My function needs to accept any number of lists, then output their symmetric difference. sym([1, 2, 3], [5, 2, 1, 4]) should return [3, 5, 4] and sym([1, 2, 5], [2, 3, 5], [3, 4, 5]) should return [1, 4, 5]. I am confused by the result of my code - this returns an empty array.
function isin(num,arra)
{
for (var i=0; i<arra.length; i++)
{
if (num == arra[i])
{
return true;
}
}
return false;
}
function sym()
{
console.log("logging args");
console.log(arguments); // logs [Array[3], Array[4]]
var syms = [];
for (var i=0; i<arguments.length-1; i++)
{
var ins = false;
for (var j=0; j<arguments[i].length; j++)
{
for (var k=i+1; k < arguments.length; k++)
{
if(isin(arguments[i][j], arguments[k]))
{
ins = true;
}
}
}
if (ins === false)
{
syms.push(arguments[i][j]);
}
}
return syms;
}
sym([1, 2, 3], [5, 2, 1, 4]);

EDITED: to add some code
Your loop variables are all global, including i. Put a var in front of them (at least before i) and you're done.
The following gets the symmetric difference of two sets. I hope you can get on from there.
function isin(num,arra)
{
for (var i=0; i<arra.length; i++)
{
if (num == arra[i]){return true;}
}
return false;
}
function sym()
{
var j,k,i,l;
var syms = [];
for ( i=0; i<arguments.length; i++)
{
var ins = false;
for (k=i+1; k < arguments.length; k++){
for ( j=0; j<arguments[i].length; j++){
if(!isin(arguments[i][j], arguments[k]))
{
syms.push(arguments[i][j]);
}
}
for ( l=0; l<arguments[k].length; l++){
if(!isin(arguments[k][l], arguments[i]))
{
syms.push(arguments[k][l]);
}
}
}
}
return syms;
}
sym([1, 2, 3], [5, 2, 1, 4]);

my code returns an array of undefined values
This is because when you are pushing onto syms, your for-loop with the j variable has completed. So it is actually at j = <arguments[i].length (now it really is an out-of-bounds index read).
if (ins === false)
{
syms.push(arguments[i][j]); # push "undefined" onto syms.
}
Make sure you put this block of code inside the for (var j=0; j<arguments[i].length; j++) block.

To solve the symmetric difference of multiple arrays, we can start by designing a function which returns the symmetric difference of two arrays
As shown in function sym2(), the main idea of getting the result from sym2(a1,a2) can be divided into two steps: (1). for every elements in array a1[], if a1[j] is not in array a2[] and a1[j] is not in the result array syms[], then a1[j] is pushed to the result array. (!isin(a1[j],syms)can prevent repeating numbers in a1[], such as sym2 ([1,1],[3]) can return [1,3] instead of [1,1,3]. after a1-a2 is done, the second step a2-a1 is performed the same way (2).for every elements in array a2[], if a2[l] is not in array a1[] and a2[l] is not in the result array syms[], then a2[l] is pushed to the result array.
function sym() take a list of arrays, first, we can save all arrays from the arguments to a variable, like arg[array1,array2,array3], and use Array.reduce() function. for example,if arg contains [a1,a2,a3] arg.reduce(function(a,b){return sym2(a,b)}); is executed like following:
syms2(a1,a2)
syms2(syms2(a1,a2),a3)
all code :
function isin(num,arra)
{
for (var i=0; i<arra.length; i++)
if (num == arra[i]){return true;}
return false;
}
function sym2(a1,a2)
{
var j,l;
var syms = [];
for ( j=0; j<a1.length; j++){
if(!isin(a1[j], a2)&&!isin(a1[j],syms))
syms.push(a1[j]);
}
for ( l=0; l<a2.length; l++){
if(!isin(a2[l], a1)&&!isin(a2[l],syms))
syms.push(a2[l]);
}
return syms;
}
function sym(){
var arg=[];
for(var o = 0; o<arguments.length;o++)
arg.push(arguments[o]);
return arg.reduce(function(a,b){
return sym2(a,b);
});
}

Related

Removing Duplicates of an Array in an Array That Has the Possible Sums of a Number

The sum Function
Problem
A beginner JS programmer here.
This question was created out of curiosity: I've created a function called sum in which takes value, a number, as an argument and returns the possible sums of that number, which was stored in variable a.
function sum(value) {
let a = [];
for(let i = 0; i <= value; i++) {
for(let j = 0; j <= value; j++) {
if(i + j === value) {
a.push([i, j]);
}
}
}
return a;
}
Using sum(5) returns [[0, 5], [1, 4], [2, 3], [3, 2], [4, 1], [5, 0]].
The question is: is there any way to remove those duplicates?
Or I want sum(5), for example, to just return [[0, 5], [1, 4], [2, 3]].
What I Tried
I tried using a Set while using the variable a as an array of i and j, but since objects are unique, the Set, b, still stored the duplicate, resulting in a Set still storing those duplicates.
function sum(value) {
let a;
let b = new Set();
for(let i = 0; i <= value; i++) {
for(let j = 0; j <= value; j++) {
a = [i, j]; // Forgot that objects are unique in JS.
b.add(a);
}
}
return b;
}
I've expected the Set to return the possible sums, but as I said, objects are unique in JS, so it still returned the duplicates.
Although you could remove the duplicates afterwards using some methods, a nicer approach would be to instead iterate only over values that will definitely sum to the target - and to stop once halfway to the target, because after that, you'd be adding duplicates.
function sum(value) {
const a = [];
for(let i = 0; i <= value / 2; i++) {
a.push([i, value - i]);
}
return a;
}
console.log(sum(5));

Determine whether array holds an almost increasing sequence

Given a sequence of integers as an array, determine whether it is possible to obtain a strictly increasing sequence by removing no more than one element from the array.
For sequence = [1, 3, 2, 1], the output should be
almostIncreasingSequence(sequence) === false
There is no one element in this array that can be removed in order to get a strictly increasing sequence.
For sequence = [1, 3, 2], the output should be
almostIncreasingSequence(sequence) === true
As you can remove 3 from the array to get the strictly increasing sequence [1, 2]. Alternately, you can remove 2 to get the strictly increasing sequence [1, 3].
Here is what I have so far:
function almostIncreasingSequence(sequence) {
//compare current int to previous, return true if greater than
//remove int at index and compare with new values, return false if comparison fails
var result = false;
for(var i = 0; i < sequence.length; i++){
var newSequence = sequence.slice();
var subSequence = newSequence.splice(i, 1);
for(var j = 0; j < newSequence.length - 1; j++){
if(newSequence === newSequence.sort((a,b) => a < b).reverse()){
result = true;
}
}
}
return result;
}
I'm trying to figure out how to solve this problem. I feel like I'm very close but for some reason when I call reverse in the conditional statement it also sorts out the newSequence variable. It's sorting two variables in the conditional, not one. As a result it resolves to true. I'm not clear why this is happening. Any feedback is appreciated.
There is no need to use a nested loop, nor to create new arrays. This can be done in O(n) time:
function almostIncreasingSequence(sequence) {
var prev = -Infinity,
beforePrev = -Infinity,
allowExceptions = true;
for (var curr of sequence) {
// Is order not maintained?
if (curr <= prev) {
// Give up when this is not the first exception
if (!allowExceptions) return false;
allowExceptions = false;
// Decide whether to skip the current or previous value
if (curr > beforePrev) prev = curr;
} else { // Normal case: keep track of two preceding values
beforePrev = prev;
prev = curr;
}
}
return true;
}
console.log(almostIncreasingSequence([1,5,3,4,8])); // true
console.log(almostIncreasingSequence([1,5,0,6,8])); // true
console.log(almostIncreasingSequence([1,5,0,4,8])); // false
sort() modifies the array in place, it doesn't return a new array. And you can't compare the contents of two arrays using ==, so that's not a good way to tell if an array is sorted. You can simply loop through the array, testing if each element is greater than the previous one.
function almostIncreasingSequence(sequence) {
for (var i = 0; i < sequence.length; i++) {
var newSequence = sequence.slice();
newSequence.splice(i, 1);
var isSorted = true;
for (j = 1; isSorted && j < newSequence.length; j++) {
if (newSequence[j] <= newSequence[j-1]) {
isSorted = false;
}
}
if (isSorted) {
return true;
}
}
return false;
}
console.log(almostIncreasingSequence([1, 3, 2, 1]));
console.log(almostIncreasingSequence([1, 3, 2]));
console.log(almostIncreasingSequence([1, 2, 3, 4, 5, 3]));
console.log(almostIncreasingSequence([8, 1, 2, 3, 4, 5]));
console.log(almostIncreasingSequence([8, 1, 2, 2, 4, 5]));

Chunk Array into groups - what's wrong with my code?

Below is the code :
function chunkArrayInGroups(arr, size) {
// Break it up.
var newArr =[];
for(var i = 0;i < arr.length;i++){
for(var j = 0;j < size;j++){
newArr.push(arr.splice(0,size));
}
}
var result = [];
for(i = 0;i < newArr.length;i++){
if(newArr[i].length != 0){
result.push(newArr[i]);
}
}
return result;
}
chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6, 7,8], 2);
This should return - [[0, 1], [2, 3], [4, 5], [6, 7], [8]]. However, the code returns [[0, 1], [2, 3], [4, 5], [6, 7]]. Also, if my input array is ([0,1,2,3,4,5,6,7,8,9,10],2) my code returns as expected.
P.S: I am specifically looking to find what's wrong with this code instead of a different code/approach altogether.
Basically you need just one loop, because you splice the array and take a chunk of the wanted size of it.
This behaviour could be used to loop until the array has a length of zero and exit the loop.
In this case the result is ready.
function chunkArrayInGroups(arr, size) {
var newArr = [];
// for (var i = 0; i < arr.length; i++) {
while (arr.length) { // add this for looping and checking
// for (var j = 0; j < size; j++) {
newArr.push(arr.splice(0, size)); // keep this for doing the work!
// }
}
// var result = [];
// for (i = 0; i < newArr.length; i++) {
// if (newArr[i].length != 0) {
// result.push(newArr[i]);
// }
// }
// return result;
return newArr; // return only newArray
}
console.log(chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6, 7, 8], 2));
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can just do the following:
var size = 2;
var arr = [0,1,2,3,4,5,6,7,8];
var newArray = [];
for(var i = 0; i < arr.length; i+=size){
newArray.push(arr.slice(i,i+size))
}
console.log(newArray); //will output [[0,1],[2,3],[4,5],[6,7],[8]]
Your problem is that you are not treating the case where the remaining in the array is less than the given size, in other words the case when arr.length < size, so the remaining items in the array won't be taken into account in the chunk array.
You need to test upon it, I updated your code so it works perfectly:
function chunkArrayInGroups(arr, size) {
// Break it up.
var newArr =[];
while(size<arr.length){
newArr.push(arr.splice(0, size ));
}
if(arr.length<size){
newArr.push(arr);
}
}
Demo:
function chunkArrayInGroups(arr, size) {
// Break it up.
var newArr =[];
while(size<arr.length){
newArr.push(arr.splice(0, size));
}
if(arr.length<size){
newArr.push(arr);
}
return newArr;
}
console.log(chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6, 7,8], 2));
Note:
There's no need for using the result array as it's just a copy of the newArr, you could just return newArr without copying it.

Looping through a filter with arguments in Javascript

Im trying to filter the zeroth arguments of the function using the other arguments of the function. The loop and filter functions seem to be working but the problem seems to be that the loop doesn't loop all the way through. I'm not exactly sure what is going on in this case. Here is the code:
function destroyer(arr) {
var args = Array.from(arguments);
args.shift();
function destroyer(value) {
for (i = 0; i <= args.length; i++) {
return value != args[i];
}
}
return arguments[0].filter(destroyer);
}
destroyer([1, 2, 3, 1, 2, 30], 2, 3);
The output is [1, 3, 1, 30].
Try doing this:
function destroyer(arr) {
var args = Array.from(arguments);
args.shift();
function destroyer(value) {
for (i = 0; i <= args.length; i++) {
if(value == args[i])
return false; //If element is found, don't return
}
return true; //Element not found in args
}
return arguments[0].filter(destroyer);
}
destroyer([1, 2, 3, 1, 2, 30], 2, 3);
EDIT: Why doesn't your approach work?
The problem is in this part:
The issue is in your return statement.
for (i = 0; i <= args.length; i++) {
return value != args[i];
}
This will return the boolean value as soon as it sees compares the value in your array to the first value in the args array, ie it only compares to the first value.

Can't get this function to remove specific elements based on subsequent arguments in javaScript

I have a initial array (the first argument in the destroyer function), followed by one or more arguments. I basically want to use the subsequent arguments as to what to eventually splice out of my array.
function destroyer(arr) {
var temp = [], j = 0;
for(var i= 1; i < arguments.length; i++){
temp.push(arguments[i]);
}
while(j < arr.length){
if(temp[j] === arr[j]){
arr.splice(j, 1);
}
j++;
}
return arr;
}
Update
I forgot to include how it would be executed, if my description was vague.
destroyer([1, 2, 3, 1, 2, 3], 2, 3) //should return [1, 1]
I just get back my original array?!
Is it a Freecodecamp challenge? It seems familiar to me.
Here is my approach to solve it.
function destroyer(arr) {
var temp = [], j = 0;
for(var i= 1; i < arguments.length; i++){
temp.push(arguments[i]);
}
var resAr=[];
while(j < arr.length){
if(temp.indexOf(arr[j])===-1){
resAr.push(arr[j])
}
j++;
}
return resAr;
}
console.log(destroyer([1, 2, 3, 1, 2, 3], 2, 3));
This should work but its big-O(n^2) as it need to search element which would be deleted
function destroyer(arr) {
var temp = Array.prototype.slice.call(arguments);
for (var i=1;i<temp.length;i++) {
for (var j=0;j<arr.length;j++) {
if (temp[i] === arr[j]) {
arr.splice(j, 1);
}
}
}
return arr;
}
console.log(destroyer([1, 2, 3, 1, 2, 3], 2, 3))
I would suggest a simpler approach that does not mutate your original array. Also has the benefit of being O(n) since using a hash.
function notDestroyer(arr) {
var lookup = {};
var result = [];
for (var i = 1; i < arguments.length; i++) {
lookup[arguments[i]] = true;
}
for (var j = 0; j < arr.length; j++) {
if (!lookup[arr[j]]) {
result.push(arr[j]);
}
}
return result;
}

Categories