Javascript Object Key Value Confusion - javascript

apologies for the stupid question. I am trying to solve this Kata on Codewars, https://www.codewars.com/kata/the-enigma-machine-part-1-the-plugboard/train/javascript/. Its basically the beginnings of an Enigma machine. I feel like I made some good progess on it. Now I'm running it through pythontutor.com but I cannot for the life of me figure out why when I run this, the second iteration of the for loop changes the property 'A' of Plugboard into 'C' and does not create a new property 'C' with value of 'A'. I am sure this is a simple concept that I am completely missing, but I sure would appreciate any insight into this.
class Plugboard {
constructor(wires) {
if(wires.length % 2 !== 0 || wires.length === 0 || wires.length > 20){
throw 'Error'
}
console.log(wires)
this.str = wires.split('')
for(var i = 0; i < this.str.length; i += 2){
if(this.hasOwnProperty(this.str[i])){
throw 'Duplicate';
}
this[this.str[i+1]] = this.str[i];
this[this.str[i]] = this.str[i+1];
}
}
process(chr){
if(!this.hasOwnProperty(chr)){
return chr
} else {
return this[chr];
}
}
}
var plugboard = new Plugboard("ABCA");

The C property does exist and has a value of "A". I ran it on repl.it, and it just works...
class Plugboard {
constructor(wires) {
if(wires.length % 2 !== 0 || wires.length === 0 || wires.length > 20){
throw 'Error'
}
console.log(wires)
this.str = wires.split('')
for(var i = 0; i < this.str.length; i += 2){
if(this.hasOwnProperty(this.str[i])){
throw 'Duplicate';
}
this[this.str[i+1]] = this.str[i];
this[this.str[i]] = this.str[i+1];
}
}
process(chr){
if(!this.hasOwnProperty(chr)){
return chr
} else {
return this[chr];
}
}
}
var plugboard = new Plugboard("ABCA");
console.log(plugboard);
console.log("Value of C:",plugboard.C);
console.log("Value of A:",plugboard.A);
console.log("Value of B:",plugboard.B);
repl.it link: https://repl.it/GJg7/2

I am guessing that you may have got the wording wrong in the question, and are actually worried about the A property containing the C value, not the reverse.
On the first loop we make the following assignments:
this["B"] = "A"
this["A"] = "B"
On the second loop we make the following assignments:
this["A"] = "C"
this["C"] = "A"
Note that this overwrites the existing value of this["A"]. It is not detected as a duplicate, because we only check this.str[i] and do not check if this.str[i+1] is a duplicate. It does not add a duplicate property, because we cannot have a duplicate property. It does exactly what it is told to do.
If this is not the desired behaviour, what is the desired behaviour?

Thank you all for your input. I realised my mistake, I was overriding the property C on my second pass. Issue solved, thanks and sorry for my ignorance

Related

recursion on returning vectors c++

Hey guys I am trying trying to right this javascript code into c++. I am doing quick sort and everything is straight forward minus the last step.
function quickSort(arr)
{
//base case if the arr is 1 or 0 then return the array
if(arr.length === 1 || arr.length === 0)
{
return arr;
}
var pivotIndex = Math.floor(arr.length/2);
var pivotValue = arr[pivotIndex];
var before = [];
var after = [];
for(var counter = 0; counter < arr.length; counter++)
{
if(counter === pivotIndex)
continue;
if(pivotValue <= arr[counter])
{
before.push(arr[counter])
}
else
{
after.push(arr[counter])
}
}
//this step I am having trouble rewriting in c++
return quickSort(after).concat(pivotValue).concat(quickSort(before));
}
I am having a hard time rewriting the recursive step in c++. I am not sure how concat 2 vector. I tried using the insert method but I keep getting an error about invalid use of void expression.
vector<int> quickSort(vector<int> arr)
{
if(arr.size() == 1 || arr.size() == 0)
{
return arr;
}
int pivotIndex = arr.size()/2;
int pivotValue = arr[pivotIndex];
vector<int> before;
vector<int> after;
//put values in before or after the piv
for(size_t counter = 0; counter < arr.size(); counter++)
{
if(counter == pivotIndex)
continue;
if(pivotValue <= arr[counter])
before.push_back( arr[counter]);
else
after.push_back( arr[counter]);
}
return //????? not sure how to do this
}
So, you realized that your core question was "how to concatenate two vectors", and you found a right answer: using insert. Now your question is about why you were getting "an error about invalid use of void expression." (That's the assumption my answer is for, at least.)
That's because you were likely trying to do something like the following:
return quickSort(after).insert( /* stuff */ );
which is wrong. In JavaScript, array.concat returns the concatenated array. It's return type is effectively Array, and so doing return arr.concat(arr2) returns an Array because arr.concat would return an Array. Further, in JavaScript, array.concat doesn't modify the array it was called on, but rather returns a new array.
In C++, however, vector.insert (#4 in the reference) returns void. That means it returns nothing. So when you try to return the result of insert, you get that error about invalid use of a void expression. Further, in C++, vector.insert does modify the vector it was called on.
So how do you use insert in this case?
vector<int> quickSort(vector<int> arr)
{
// ...
// Sort `before` and `after`
before = quickSort(before);
after = quickSort(after);
// Modify `after` and return it.
after.push_back(pivotValue);
after.insert(after.end(), before.begin(), before.end());
return after;
}
Note: My code isn't optimal and the idea of rewriting JS in C++ is also oddly specific. My answer is to simply outline the problem asked in the question, not to give a good C++ implementation of quick sort.
To concat two vector , you can use std::merge
like:std::merge(v1.begin(), v1.end(), v2.begin(), v2.end(), std::back_inserter(dst));

Why is the first argument of reduce() returning undefined?

I'm trying to write a function that takes in an array as an input. If the integer is positive, it counts it. If the integer is negative, it sums it.
I figured that that the reduce() helper in js would be the best way to go about this, but I keep returning undefined for my first argument when it runs.
Here's my code:
function countPositivesSumNegatives(input) {
let countPositive = 0;
let sumNegative = 0
if (input === null || input === []){
return [];
} else {
return input.reduce(function(prev,num){
if (num > 0) {
countPositive++;
}else{
sumNegative = prev + num};
}, 0);
}
return [countPositive, sumNegative];
}
It throws me a TypeError that says:
TypeError: Cannot read property '0' of undefined
When I log 'prev' to the console inside of the reduce function, it logs undefined for all inputs except the first one. The first one, as expected, is 0. But for each following input it logs undefined. Why is this happening?
Thanks in advance.
The callback you pass to .reduce() needs to return the cumulative value (the value that will be passed as prev to the next iteration of the loop. Since you are returning nothing, you get undefined for the next iteration of your loop.
This complicates what you're trying to do because you are trying to keep track of two values in your loop. As such, you would either have to avoid using prev at all or you'd have to make it be a data structure that had both your values in it. Your use is not a textbook example for .reduce(). Your code is probably simpler with an iteration using .forEach() or for/of.
function countPositivesSumNegatives(input) {
let countPositive = 0;
let sumNegative = 0
if (!input || input.length === 0){
return [];
} else {
input.forEach(function(num){
if (num > 0) {
++countPositive;
} else {
sumNegative += num;
});
}
return [countPositive, sumNegative];
}
Well sorry but this is not a good implementation of this function. But we can correct your function as follows;
function countPositivesSumNegatives(input) {
let countPositive = 0;
let sumNegative = 0;
if (input === null || input === []){
return [];
} else {
sumNegative = input.reduce(function(prev,num){
if (num > 0) {
countPositive++;
} else {
prev += num;
}
return prev; // <---- THE MISSING PART
}, 0);
}
return [countPositive, sumNegative];
}
var data = [1,2,3,4,5,-4,7,-3];
console.log(countPositivesSumNegatives(data));
However while the code works just fine it still involves many issues. When getting into functors like .reduce() you should be able to keep everthing contained within itself and should not refer to variables at the outer scope. Accordingly one can simply rephrase this code as follows;
var data = [1,2,3,4,5,-4,7,-3],
cpsn = a => a.reduce((p,c) => c > 0 ? (p[0]++,p) : (p[1]+=c,p) ,[0,0]);
console.log(cpsn(data))

need help understanding using an associative array to keep track of array value appearances

code:
method = function(a) {
//use associative array to keep track of the total number of appearances of a value
//in the array
var counts = [];
for(var i = 0; i <= a.length; i++) {
if(counts[a[i]] === undefined) {
//if the condition is looking for a[0],a[1],a[2],a[3],a[4],a[5] inside counts[] one value at a time and does not find them inside counts[] it will set each value to 1
counts[a[i]] = 1;
console.log(counts[a[i]]);
} else {
return true;
}
}
return false;
}
the js console logs 1x6
how can the condition see if a value inside counts[a[i]] has been repeated if all of the counts[a[i]] values are being set to 1 each iteration? wouldn't it always be comparing 1 to 1?
for example, if the a array is [1,2,3,4,5,2] and counts[a[1]](first int 2 in the array) is undefined and then set to 1, how would the condition know that counts[a[5]](second int 2 in the array) is the same value as counts[a[1]] and therefore it should return true?
perhaps I am misunderstanding whats going on.
I would appreciate any help. thanks
function counter(){
this.counts=[];
}
counter.prototype.add=function(a){
if(this.counts[a] === undefined) {
this.counts[a] = 1;
console.log(this.counts);
} else {
return true;
}
return false;
}
try this:
c= new counter();
c.counts;//[]
c.add(1);
c.counts;//[ ,1]
c.add(5);
c.counts;//[ ,1, , , ,1]
c.add(1);//true
...
may it helps you to understand whats going on

JavaScript Throws Undefined Error

What it is supposed to do -
Example
url1(pages,"ALT") returns "www.xyz.ac.uk"
url1(pages,"xyz") returns ""
The error - TypeError: Cannot call method 'toUpperCase' of undefined
This is just for some coursework, Im stuck with these errors. Any help would be much appreciated
function index(string,pattern,caseSensitive) {
if(caseSensitive == false) {
var v = string.toUpperCase();
} else {
var v = string;
}
return indexNumber = v.indexOf(pattern);
}
var pages = [ "|www.lboro.ac.uk|Loughborough University offers degree programmes and world class research.", "!www.xyz.ac.uk!An alternative University" , "%www%Yet another University"];
alert(url1(pages, "ALT"));
function url1(pages,pattern) {
var siteContent = [];
for(i=0;i<pages.length;i++) {
var seperator = pages[i].charAt(0);
if(pages[i].indexOf(seperator)>0){
siteContent = pages[i].split(pages[i].indexOf(seperator));
}
if( index(siteContent[2],pattern,false)>=0){
return siteContent[1];
}else{
return "";
}
}
}
if(pages[i].indexOf(seperator)>0){
siteContent = pages[i].split(pages[i].indexOf(seperator));
}
if( index(siteContent[2],pattern,false)>=0){
return siteContent[1];
}else{
return "";
}
If pages[i].indexOf(seperator)<=0, siteContent is still whatever it was from the last iteration. If that happens on the first iteration, siteContent is still [], and siteContent[2] is undefined.
Another problem: the expression pages[i].indexOf(seperator) returns a number, and pages[i].split expects a delimiting string as an argument. Since the number doesn't appear in your input, you'll always get a single-element array, and siteContent[2] will always be undefined. Get rid of .indexOf(seperator), change it to siteContent = pages[i].split(seperator).
One more: get rid of the else { return ""; }. Add a return ""; after the for loop.
Finally, in the first if statement condition, change .indexOf(seperator) > 0 to .indexOf(seperator, 1) !== -1. Since you're getting seperator from the first character of the string, it will be found at 0. You want the second occurrence, so start the search at 1. In addition, .indexOf returns -1 if it doesn't find the substring. You'll need to account for this in both if conditions.
Side note, as this is not causing your problem: never use == false. JS will coerce stuff like 0 and "" to == false. If that's what you want, just use the ! operator, because the expression has nothing to do with the value false.
My final answer is http://jsfiddle.net/QF237/
Right here:
alert(url1(pages, ALT)); // ALT ISN'T DEFINED
I believe you forgot to quote it:
alert(url1(pages, "ALT"));
You should split the string passing the separator character itself. Your function then will look like:
function url1(pages,pattern) {
var siteContent = [];
for(i=0;i<pages.length;i++) {
var seperator = pages[i].charAt(0);
console.log(seperator);
if(pages[i].indexOf(seperator)>=0){
siteContent = pages[i].split(seperator); //fixed here
}
console.log(siteContent);
if( index(siteContent[2],pattern,false)>=0){
return siteContent[1];
}else{
return "";
}
}
}
Tell us if it worked, please.
EDIT: It seeems your index() also has a little problem. Please try the function below.
function index(string,pattern,caseSensitive) {
var v;
if(caseSensitive == false) {
v = string.toUpperCase();
pattern = pattern.toUpperCase(); //to clarify: pattern should be uppercased also if caseSensitiveness is false
} else {
v = string;
}
return v.indexOf(pattern);
}
EDIT 2:
And url1() is finally like this:
function url1(pages,pattern) {
var siteContent = [];
for(i=0;i<pages.length;i++) {
var seperator = pages[i].charAt(0);
if(pages[i].indexOf(seperator)>=0){
siteContent = pages[i].split(seperator);
}
if( index(siteContent[2],pattern,false)>=0){
return siteContent[1];
}
}
return "";
}
In this case, the first occurrence of pattern in all pages will be returned.

TypeError: x[0] is undefined, where x is itself an array

I have a JS function part of which reads:
for (i = 0; i < kodoj.length; i++) {
var x = document.getElementsByName(kodoj[i]);
if (kodoj[i]=="zh-CN") {
var y = document.getElementsByName("zh-TW");
if (x[0].checked || y[0].checked) { /*do this*/ }
else if (x[1].checked || y[1].checked) { /*do this*/ }
else if (x[2].checked && y[2].checked) { /*continue*/ }
else {
alert("........");
return;
}
}
else if etc.
I get "x[0] is undefined", but never "x[1] or x[2] is undefined"
Having read some similar problems with declaring twodimensional arrays,
I adde in the above part of the function var x = document.getElementsByName("zh-CN");
but that did not help.
I am just a self-learning programmer, so any special features like queries and so on are not known to me.
Could anybody help me?
I guess you should change the value of i=0 to i=1
kodoj[0] will give you null so henceyour getting "x[0] is undefined" error
Are you sure that x is not an empty array?
You might never get "x[1] or x[2] is undefined" because execution never comes this far in the case of x being empty.

Categories