0

I have a long javascript string. I am trying to break it into an array with every x combination of consecutive words. So for example if my array

var string = 'This is my example string'

and my x was equal to 3 I would get something like:

['This', 'This is', 'This is my', 'is', 'is my', 'is my example', 'my', 'my example', 'my example string', 'example string', 'string']

So like, every combination of up to three words. I am using this as an index to do fuzzy text matching on.

goddamnyouryan
  • 6,854
  • 15
  • 56
  • 105
  • 1
    Do a `.split(' ')` to convert it to an array of single words. Every single individual word is in there, then pick consecutive 2 words by index and consecutive 3 words by index, up to consecutive x words. Will be a double loop. – nurdyguy Jan 31 '19 at 20:39
  • 1
    Does the order of the array matter? – Pavlo Jan 31 '19 at 20:43
  • 1
    Check javascript array permutations, possible solution here: https://stackoverflow.com/questions/23305747/javascript-permutation-generator-with-permutation-length-parameter – arunes Jan 31 '19 at 20:47
  • 1
    The entry "example" is missing? – trincot Jan 31 '19 at 20:53

3 Answers3

3

You could use a double for loop:

function chunks(str, len) {
    const arr = str.match(/\S+/g);
    const result = [];
    for (let i = 0; i < arr.length; i++) {
        const end = Math.min(arr.length, i + len);
        for (let j = i + 1; j <= end; j++) {
            result.push(arr.slice(i, j).join(" "));
        }
    }
    return result;
}


var string = 'This is my example string';
console.log(chunks(string, 3));

And a more functional approach would be:

function chunks(str, len) {
    return str.match(/\S+/g).flatMap((_, i, arr) => 
        arr.slice(i, i + len).map((_, j) => arr.slice(i, i+j+1).join(" "))
    );
}

var string = 'This is my example string';
console.log(chunks(string, 3));
trincot
  • 317,000
  • 35
  • 244
  • 286
2

You could reduce the array and take a Set for getting unque values.

var string = 'This is my example string',
    result = [... new Set(string.split(' ').reduce((r, s, i, a) =>
        r.concat(
            s,
            a.slice(i, i + 2).join(' '),
            a.slice(i, i + 3).join(' ')
        ),
        []
    ))];

console.log(result);
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
1

A purely functional approach:

// permuteWords :: Number -> String -> [String]
const permuteWords = count => x => {
    const words = x.split (' ')
    const wordIndexes = [...words.keys ()]

    return wordIndexes.flatMap (i => {
        const wordIndexes_ = wordIndexes.slice (i, count + i)

        return wordIndexes_.map (i_ => 
            words.slice (i, i_ + 1).join (' ')
        )
    })
}

const output = permuteWords (3) ('This is my example string')

console.log (output)

2nd take: More segmentation to make things simpler!

Now I've defined permuteBy to produce a flat array of indices representing the permutations, and I use them to sequentially get each word:

// rangeFromZero :: Number -> [Number]
const rangeFromZero = x => [...Array (x).keys ()]

// permuteBy :: Number -> Number -> [Number]
const permuteBy = x => y => {
    const ys = rangeFromZero (y)

    return ys.flatMap(i => 
        ys.slice (i, x + i).flatMap (i_ => ys.slice(i, i_ + 1))
    )
}

// permuteWords :: Number -> String -> [String]
const permuteWords = count => x => {
    const words = x.split (' ')
    
    return permuteBy (count) (words.length)
                  .map (i => words[i])
}

const output = permuteWords (3) ('This is my example string')

console.log (output)
Matías Fidemraizer
  • 63,804
  • 18
  • 124
  • 206