cam c
cam c

Reputation: 29

How to create specific chain of numbers

I have a school prompt to create a function that finds out which integer, in the range that the user enters, produces the longest chain. The "chain" consists of:

E.g. if you start with 3, the sequence will be 3-10-5-16-8-4-2-1. The function will print out the number that produces the longest chain and the actual integers in that chain (length of the chain).

This is what I have so far. I can't figure it out.

function chain2()
        var startNumber = prompt("Enter starting number of range", "4");
        var endNumber = prompt ("Enter ending number of range", "9")

        var separator="-";
        while (currentNumber>1){
            if (currentNumber%2==1){
                currentNumber=currentNumber*3+1;
                chain+=separator+currentNumber;
            }
            else if (currentNumber%2==0){
                currentNumber=currentNumber/2;
                chain+=separator+currentNumber;
            }

        }
        return chain;
        }
        document.write(chain());

Upvotes: 1

Views: 186

Answers (1)

Mulan
Mulan

Reputation: 135425

As a homework assignment, I should nudge you rather than just give you the answer. If there's a single point of advice I would give you, it's that you should separate your work into easy-to-understand functions first. Writing one big function that does everything is a recipe for a disaster. The function you have right now

  • gives two prompts for user input
  • loops based on the user inputs
  • determines even and odd values
  • performs basic arithmetic according to the Collatz chain procedure

Breaking this into separate parts will make it much easier to reason about your code. I start from the top-level function that I wish would work, and then work my way down from there.

function FindMaxCollatzInRange(x,y) {
  // max = ...
  // ...
  return max;
}

If you find yourself needing other functions, that's perfectly normal. Write them as you need them.

Your basic algorithm should do something like this:

  • for numbers between min and max (inclusive) ...
  • compute and record the collatz chain length for each number
  • based on the recorded lengths, return the number with the highest length

So here's how I would do this. This is way beyond the scope of a JavaScript homework assignment, but I found it fun to work on.

I'm OK posting this code because I know it can't directly be copy/pasted as an answer for your assignment. My hope is that there will be some things here that will encourage you to explore some of the techniques used.

// compute the collatz chain for a given number, x
const collatz = Y (f=> y=> x=> {
  if (x === 1)   return append (x) (y);
  if (isEven(x)) return f (append (x) (y)) (x/2);
  else           return f (append (x) (y)) (x*3 + 1);
}) ([]);

// compute the length of a collatz chain
const collatzLen = comp (len) (collatz);

// create a range from minimum, n, to maximum, m
const range = Y (f=> r=> n=> m=> {
  if (n > m)  return r;
  else        return f (append (n) (r)) (n+1) (m);
}) ([]);

// compute the maximum collatz chain length for a given range
const maxCollatz = (n,m) =>
  comp (foldl (([x,xlen])=> ([y,ylen])=> ylen > xlen ? [y,ylen] : [x,xlen]) ([0,1]))
       (map (n=> [n,collatzLen (n)]))
       (range (n) (m));

Here's some sample output of the functions so you can see what's going on

collatz (3)
//=> [ 3, 10, 5, 16, 8, 4, 2, 1 ]

collatzLen (3)
//=> 8

range (3) (10)
//=> [ 3, 4, 5, 6, 7, 8, 9, 10 ]

maxCollatz (3,10)
//=> [ 9, 20 ]

The way to read that last output [ 9, 20 ] is, "The number 9 has the longest Collatz chain length, with a length of 20"

Simply put, each function is responsible for doing exactly one thing. The function that answers your problem is the maxCollatz function, which computes a list of chain lengths using collatzLen for each element in the range. Lastly, the list is reduced to determine which number has the longest chain.

Here are the generic dependencies

const comp = f=> g=> x=> f (g (x));
const mod = x=> y=> y % x;
const eq = x=> y=> y === x;
const isEven = comp (eq (0)) (mod (2));
const prop = x=> y=> y [x];
const len = prop ('length');
const concat = x=> xs=> xs .concat (x);
const append = x=> concat ([x]);
const foldl = f=> y=> xs=> xs .reduce ((x,y)=> f (x) (y), y);
const map = f=> xs=> xs .map (x=> f(x));

// U-combinator
const U = f=> f (f);

// Y-combinator
const Y = U (h=> f=> f (x=> h (h) (f) (x)));

Additional reading:

Upvotes: 1

Related Questions