skip to Main Content

I am trying to find the solution for the below ask –

Create a function that accepts a chemical compound (H2O) string and returns a JSON object containing key-value pairs where keys are the element symbols and the values are the element counts.

"H2O" => {"H": 2, "O": 1}
"C6H12" => {"C": 6, "H": 12}
"COOH" => {"C": 1, "O": 2, "H": 1}

I have written a solution –

  function parseChemicalCompound(chemical) {
      let result = {};
      let currentElement = "";
      let currentCount = ""; // Initialize as string to handle leading digits
    
      for (let i = 0; i < chemical.length; i++) {
        let char = chemical[i];
        let nextChar = i < chemical.length - 1 ? chemical[i + 1] : ""; // Access next character safely
    
        if (char >= "A" && char <= "Z") {
          // Handle element completion
          if (currentElement !== "") {
            if (currentCount === "") currentCount = "1"; // Default to 1 if no count
            result[currentElement] = parseInt(currentCount);
          }
          currentElement = char;
          currentCount = ""; // Reset for the new element
        } else if (char >= "a" && char <= "z") {
          currentElement += char; // Handle multi-letter elements
        } else if (!isNaN(parseInt(char))) {
          currentCount += char; // Append digits for counts
        } else if (char === nextChar) {
          // Handle consecutive identical characters for counts
          currentCount += char;
          // i++; // Skip the next character since it's already processed
        } else {
          // Optionally handle invalid characters
          console.warn(`Invalid character: ${char}`);
        }
      }
    
      // Handle the last element
      if (currentElement !== "") {
        if (currentCount === "") currentCount = "1"; // Default to 1 if no count
        result[currentElement] = parseInt(currentCount);
      }
    
      return result;
    }

code sandbox – https://codesandbox.io/p/sandbox/basic-javascript-forked-mzpk49?file=%2Fsrc%2Findex.js%3A5%2C1

But this doesn’t work for the last test case

"COOH" =>
For this it always gives

{"C": 1, "O": 1, "H": 1}

But the result should have "O": 2

{"C": 1, "O": 2, "H": 1}

Suggest some good answers.

2

Answers


  1. Instead of looping character by character, use a regular expression. Each element can be matched with the regexp ([A-Z][a-z]?)(d*). The first capture group is the element abbreviation (an uppercase letter optionally followed by a lower case letter), the second group is the optional atom count. Loop over all the matches to create the object.

    function parseCompound(compound) {
      let matches = compound.matchAll(/([A-z][a-z]?)(d*)/g);
      let result = {};
      for (let [m, element, count] of matches) {
        if (!count) {
          count = 1;
        } else {
          count = parseInt(count);
        }
        if (result[element]) {
          result[element] += count;
        } else {
          result[element] = count;
        }
      }
      return result;
    }
    
    console.log(parseCompound('H2O'));
    console.log(parseCompound('He2O3'));
    console.log(parseCompound('C6H12'));
    console.log(parseCompound('COOH'));
    Login or Signup to reply.
  2. You were really close! You just need to add to the total (result) instead of assigning a new total.

    Summary of changes

    So, instead of just assigning:

    result[currentElement] = parseInt(currentCount);
    

    You should add the current count to keep a running total.

    result[currentElement] = (result[currentElement] ?? 0) + parseInt(currentCount);
    

    If the result doesn’t exist, treat it as zero. Note this change needs to be made in both (2) places.

    Also, the branch that checks if the chars are the same is not necessary. You can remove the check and the block that follows it.

        } else if (char === nextChar) {
    

    Full example:

    function parseChemicalCompound(chemical) {
      let result = {};
      let currentElement = "";
      let currentCount = ""; // Initialize as string to handle leading digits
    
      for (let i = 0; i < chemical.length; i++) {
        let char = chemical[i];
        let nextChar = i < chemical.length - 1 ? chemical[i + 1] : ""; // Access next character safely
    
        if (char >= "A" && char <= "Z") {
          // Handle element completion
          if (currentElement !== "") {
            if (currentCount === "") currentCount = "1"; // Default to 1 if no count
            result[currentElement] = (result[currentElement] ?? 0) + parseInt(currentCount);
          }
          currentElement = char;
          currentCount = ""; // Reset for the new element
        } else if (char >= "a" && char <= "z") {
          currentElement += char; // Handle multi-letter elements
        } else if (!isNaN(parseInt(char))) {
          currentCount += char; // Append digits for counts
        } else {
          // Optionally handle invalid characters
          console.warn(`Invalid character: ${char}`);
        }
      }
    
      // Handle the last element
      if (currentElement !== "") {
        if (currentCount === "") currentCount = "1"; // Default to 1 if no count
        result[currentElement] = (result[currentElement] ?? 0) + parseInt(currentCount);
      }
    
      return result;
    }
    console.log(parseChemicalCompound("COOH"));
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search