0

I need to change array A to be like array B, making sure the hashed item becomes the before of any number of non hashed items, until the next hashed item

const A = [ '# test',
  'test',
  '# layouts',
  'main',
  'nav' ]

const B = ['test/test',
    'layouts/main',
    'layouts/nav' ]
1
  • 1
    Step 1, don't use a const for something you want to change. Commented Dec 11, 2018 at 21:12

3 Answers 3

1

You can use reduce for this, the accumulator should be an object containing two values, the first will be the results array and the other will be the current hash string to be used within reduce to generate the paths. Once reduce finishes its work we can store the result property of the accumulator into our result variable B:

const B = A.reduce((acc, str) => {                           // for each string in the array A
   if(str.indexOf("#") === 0) {                              // if the string is hashed one
      acc.currentHash = str.slice(2);                        // set the current hash to this string
   } else {                                                  // otherwise
      acc.result.push(acc.currentHash + "/" + str);          // use the current hash to generate the resulting string of the current string
   }
   return acc;
}, { result: [], currentHash: ""}).result;                   // once reduce finishes, use '.result' to access the result array of the accumulator

Example:

const A = [ '# test', 'test', '# layouts', 'main', 'nav' ];

const B = A.reduce((acc, str) => {
   if(str.indexOf("#") === 0) {
      acc.currentHash = str.slice(2);
   } else {
      acc.result.push(acc.currentHash + "/" + str);
   }
   return acc;
}, { result: [], currentHash: ""}).result;

console.log(B);

Sign up to request clarification or add additional context in comments.

Comments

1

My preferred approach would be to map the array to the desired format and then filter out the extraneous markers.

const needle = '# ';
let directoryName = '';
const b = a.map((elem) => {
    if (elem.startsWith(needle)) {
        directoryName = elem.substring(needle.length);
        return;
    }
    return directoryName + '/' + elem;
}).filter(Boolean);

Note that I have optimized the code for readability. It will loop over the array twice, which is almost certainly fine, since the operations here are very fast. But if you have a huge array and need every bit of performance, Ibrahim's answer would be more appropriate.

Comments

0

Here's an approach you can take that utilizes Array.prototype.reduce and Object.keys

function modify(a, delimiter) {
  const f = a.reduce((accum, el) => {
    var s = el.replace(/\s/g, '');
    if (s.charAt(0) === delimiter) {
      accum.pointer = s.substring(1);
      accum.data[accum.pointer] = [];
    } else {
      accum.data[accum.pointer].push(el);
    }
    return accum;
  }, {
    pointer: null,
    data: {}
  });

  return Object.keys(f.data).map(k => {
    var s = `${delimiter}${k}`
    var values = f.data[k];
    values.forEach(v => {
      s += `/${v}`
    });
    return s;
  });
}

const A = ['# test',
  'test',
  '# layouts',
  'main',
  'nav'
]

const B = modify(A, "#");
console.log(B);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.