skip to Main Content

I need to make a function so that it will return the starting and ending index of the widest pasture as well as the width.

It needs to return an array in this particular order.

[length, starting_index, ending_index]

As an example, for "_-___-__-____-______-_", the return value should be [6, 14, 19].

If there are multiple pastures that have the same length, return the position of the pasture towards the end of the array.

As an example, for "_-___-__-___-", the return value should be [3, 9, 11].

If the widest pasture length is 0, such as "---", return 0 for all the values [0, 0, 0].

var widestPasture = function (landscape) {
  // Implement your code below
  let array = landscape.split("-");
  let greatest;
  let tillGreatest = 0;
  let endIndex;
  let answer = [];

  for (let i = 0; i < array.length; i++) {
    if (array[i + 1] !== undefined) {
      greatest = array[i].length;
    }
  }
  
  for (let i = 0; i < array.length; i++) {
    if (array[i].length < greatest) {
      tillGreatest += array[i].length;
    }
  }
  
  let startIndex = tillGreatest += 1;
  
  tillGreatest += 2;
  
  endIndex = tillGreatest + greatest -1;

  answer = [greatest, tillGreatest, endIndex];
  
  return answer;
};

console.log(widestPasture("_-___-__-____-______-_"));
// -> [6, 14, 19]
console.log(widestPasture("_-___-__-___-"));
// -> [3, 9, 11]

The issue I’m running into is figuring out how to output the [3, 9, 11]. Currently the second output is [3, 6, 8]. It feels like the solution is something simple right in my face but I can’t grasp it and all my other attempts have resulted is breaking the currently working code.

Is my only option rewriting from the beginning?

5

Answers


  1. The first problem is that the variable greatest is set to one-but-last partition without comparing which partition is the longest. Even if the first partition would be the longest, greatest will still be overwritten with the length of a next array — even when it is shorter.

    Secondly, the tillGreatest variable gets the sum of the lengths of arrays that are shorter than the greatest. But this will also include lengths of arrays that come after the greatest.

    Another issue is that you lose track of the starting indices because of the split. You try to overcome this with += 1 and += 2, but this is not generic enough. Honestly, the split into partitions made this harder than necessary.

    I would suggest not to do the split, but just iterate each character of the landscape string and keep track of the starting index of the current series of _, and derive its length. Then you can update the answer array whenever you get a length that is greater than what was registered before.

    Here is how that looks:

    var widestPasture = function (landscape) {
        let answer = [0, 0, 0];
        for (let i = 0, start = 0; i < landscape.length; i++) {
            if (landscape[i] != "_") {
                start = i + 1;
            } else if (i + 1 - start >= answer[0]) {
                answer = [i + 1 - start, start, i];
            }
        }
        return answer;
    };
    
    console.log(widestPasture("_-___-__-____-______-_"));
    // -> [6, 14, 19]
    console.log(widestPasture("_-___-__-___-"));
    // -> [3, 9, 11]
    Login or Signup to reply.
  2. I was going to type Trincots explanation regarding the greatest variable, so I won’t repeat that here, and their solution is great. Here’s an alternative solution so you can see different ways of getting to it

    var widestPasture = function (landscape) {
      let array = landscape.split("-");
      let longest = Math.max(...(array.map(el => el.length)));
      let pos = array.lastIndexOf("_".repeat(longest));
      //reconstruct
      let c =0, firstIndex=0;
      while (c<pos) {
       firstIndex += array[c].length +1;
       c++;
       }
      let answer = [longest, firstIndex, firstIndex+longest-1];
      return answer;
    };
    
    console.log(widestPasture("_-___-__-____-______-_"));
    // -> [6, 14, 19]
    console.log(widestPasture("_-___-__-___-"));
    // -> [3, 9, 11]
    Login or Signup to reply.
  3. A feasible approach utilizes matchAll which is going to match this simple regex … /_+/g … a sequence of underscore characters (globally).

    The result array contains matching items where each item features the match itself (the underscore sequence) and e.g. the index property which indicates the match’s starting position.

    sorting the array of matching items, by each item’s match length in an ascending order, will feature the OP’s matching result of interest as the sorted array’s last item. From this very item one can create/assemble the result array which the OP is looking for.

    function getLastValidMatchingPastureData(value) {
      const lastValidPastureMatch = [...String(value).matchAll(/_+/g)]
        // sort each matching pasture data item ascending by `length`.
        .sort(([a], [b]) => a.length - b.length)
        // access/get the last matching item (the last longest item).
        .at(-1);
    
      return [ // assemble the data of OP's interest.
        lastValidPastureMatch[0].length,
        lastValidPastureMatch.index,
        lastValidPastureMatch.index + lastValidPastureMatch[0].length - 1,
      ];
    }
    
    console.log( // [3, 9, 11]
      '"_-___-__-___-" ... ',
      getLastValidMatchingPastureData("_-___-__-___-"),
    );
    console.log( // [6, 14, 19]
      '"_-___-__-____-______-_" ... ',
      getLastValidMatchingPastureData("_-___-__-____-______-_"),
    );
    console.log( // [6, 21, 26]
      '"_-___-__-______-____-______-_" ... ',
      getLastValidMatchingPastureData("_-___-__-______-____-______-_"),
    );
    .as-console-wrapper { min-height: 100%!important; top: 0; }
    Login or Signup to reply.
  4. You can find a simple solution below which loops through the input characters, finds the pastures and whenever it finds a better pasture than the best so far it will become the new best so far. You can find detailed explanation between the lines.

    function widestPasture(input) {
        //At the very start we do not have a solution yet, do we default bestSofar to undefined
        let bestSofar = undefined;
        //lastStartIndex being negative means we are currently not inside a pasture
        let lastStartIndex = -1;
        //we loop the indexes of the string
        for (let i = 0; i < input.length; i++) {
            //we check whether the current character is outside of a pasture
            if (input[i] !== '_') {
                //if so, and we were in a pasture just before, then we found the end of
                //the current pasture at the previous index of i - 1
                if (lastStartIndex >= 0) {
                    //we create a solution array in order to compare to the best so far
                    let currentPasture = [i - lastStartIndex, lastStartIndex, i - 1];
                    //if we did not have a best earlier, or the best so far is not
                    //strictly worse than our current solution, then we replace bestSofar
                    //with the currentPasture
                    if ((!bestSofar) || (bestSofar[0] <= currentPasture[0])) bestSofar = currentPasture;
                    //since we have left the pasture, we mark lastStartIndex with a negative
                    //value so we will be aware that we are not inside a pasture
                    lastStartIndex = -1;
                }
            //the else here means that the character is '_', so that we are inside a pasture
            } else if (lastStartIndex < 0) lastStartIndex = i;
        }
        //After the loop we check whether we were inside a pasture at the last character
        //to cover (literally) edge-cases
        if (lastStartIndex >= 0) {
            //We create the currentPasture array
            let currentPasture = [input.length - lastStartIndex, lastStartIndex, input.length - 1];
            //and compare it with the best so far and if it's better, then it will become
            //the new best
            if ((!bestSofar) || (bestSofar[0] <= currentPasture[0])) bestSofar = currentPasture;
        }
        return bestSofar;
    }
    console.log(widestPasture("_-___-__-____-______-_"));
    // -> [6, 14, 19]
    console.log(widestPasture("_-___-__-___-"));
    // -> [3, 9, 11]
    console.log(widestPasture("_-__-___"));
    // -> [3, 5, 7]

    This is how the solution looks alike without the comments

    function widestPasture(input) {
        let bestSofar = undefined;
        let lastStartIndex = -1;
        for (let i = 0; i < input.length; i++) {
            if (input[i] !== '_') {
                if (lastStartIndex >= 0) {
                    let currentPasture = [i - lastStartIndex, lastStartIndex, i - 1];
                    if ((!bestSofar) || (bestSofar[0] <= currentPasture[0])) bestSofar = currentPasture;
                    lastStartIndex = -1;
                }
            } else if (lastStartIndex < 0) lastStartIndex = i;
        }
        if (lastStartIndex >= 0) {
            let currentPasture = [input.length - lastStartIndex, lastStartIndex, input.length - 1];
            if ((!bestSofar) || (bestSofar[0] <= currentPasture[0])) bestSofar = currentPasture;
        }
        return bestSofar;
    }
    
    Login or Signup to reply.
  5. Just to explore various ways to accomplish the same functionality, we can use Regular Expressions and matchAll method of Strings.

    /_+/g is a Regular Expression defined in JavaScript. To define a Regular Expression in JavaScript we begin and end with / (slash) character. Then we write the rules between these shales. Here, I wrote _+ to match occurences with at least one or more underscores. After the ending slash we can type some additional characters to define flags of our Regular Expression; by typing g after the expression, we define a global expression. Global flag allows to match all occurences for the given string, otherwise we would only match the first occurence. To use matchAll method, we need to have a global Regular Expression. Below code uses these features:

    function widestPasture(landscape) {
        const expression = /_+/g;
        var result = [0, 0, 0];
        var allMatches = landscape.matchAll(expression);
        var currentMatch = allMatches.next();
        
        while(!currentMatch.done) {
            let { 0: value, index: tillGreatest } = currentMatch.value;
            if(value.length >= result[0]) {
                result[0] = value.length;
                result[1] = tillGreatest;
                result[2] = tillGreatest+(value.length-1)
            }
            currentMatch = allMatches.next();
        }
        
        return result;
    }
    
    console.log(widestPasture("_-___-__-____-______-_"));
    // Output: [6, 14, 19]
    console.log(widestPasture("_-___-__-___-"));
    // Output: [3, 9, 11]
    console.log(widestPasture("---"));
    // Output: [0, 0, 0]
    

    Side note: To test regular expressions easily and explore more about them, you can visit RegExr. It has a nice, clean and very helpful UI. If you ever need to work with Regular Expressions, this website is a must-have tool.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search