240 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			240 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| ---
 | |
| id: 5ea2815e364d9a2222ea55f8
 | |
| title: LZW compression
 | |
| challengeType: 5
 | |
| forumTopicId: 385288
 | |
| dashedName: lzw-compression
 | |
| ---
 | |
| 
 | |
| # --description--
 | |
| 
 | |
| The Lempel-Ziv-Welch (LZW) algorithm provides loss-less data compression.
 | |
| 
 | |
| You can read a complete description of it in the [Wikipedia article](https://en.wikipedia.org/wiki/Lempel-Ziv-Welch) on the subject.
 | |
| 
 | |
| # --instructions--
 | |
| 
 | |
| Write a function that takes two parameters. The first parameter is a boolean where `true` indicates compress and `false` indicates decompress. The second parameter is either a string or an array to be processed. If it is a string to be compressed, return an array of numbers. If it's an array of numbers to be decompressed, return a string.
 | |
| 
 | |
| # --hints--
 | |
| 
 | |
| `LZW` should be a function.
 | |
| 
 | |
| ```js
 | |
| assert(typeof LZW === 'function');
 | |
| ```
 | |
| 
 | |
| `LZW(true, "TOBEORNOTTOBEORTOBEORNOT")` should return a array.
 | |
| 
 | |
| ```js
 | |
| assert(Array.isArray(LZW(true, 'TOBEORNOTTOBEORTOBEORNOT')));
 | |
| ```
 | |
| 
 | |
| `LZW(false, [84, 79, 66, 69, 79, 82, 78, 79, 84, 256, 258, 260, 265, 259, 261, 263])` should return a string.
 | |
| 
 | |
| ```js
 | |
| assert(
 | |
|   typeof LZW(false, [
 | |
|     84,
 | |
|     79,
 | |
|     66,
 | |
|     69,
 | |
|     79,
 | |
|     82,
 | |
|     78,
 | |
|     79,
 | |
|     84,
 | |
|     256,
 | |
|     258,
 | |
|     260,
 | |
|     265,
 | |
|     259,
 | |
|     261,
 | |
|     263
 | |
|   ]) === 'string'
 | |
| );
 | |
| ```
 | |
| 
 | |
| `LZW(true, "TOBEORNOTTOBEORTOBEORNOT")` should return `[84, 79, 66, 69, 79, 82, 78, 79, 84, 256, 258, 260, 265, 259, 261, 263]`.
 | |
| 
 | |
| ```js
 | |
| assert.deepEqual(LZW(true, 'TOBEORNOTTOBEORTOBEORNOT'), [
 | |
|   84,
 | |
|   79,
 | |
|   66,
 | |
|   69,
 | |
|   79,
 | |
|   82,
 | |
|   78,
 | |
|   79,
 | |
|   84,
 | |
|   256,
 | |
|   258,
 | |
|   260,
 | |
|   265,
 | |
|   259,
 | |
|   261,
 | |
|   263
 | |
| ]);
 | |
| ```
 | |
| 
 | |
| `LZW(false, [84, 79, 66, 69, 79, 82, 78, 79, 84, 256, 258, 260, 265, 259, 261, 263])` should return `"TOBEORNOTTOBEORTOBEORNOT"`.
 | |
| 
 | |
| ```js
 | |
| assert.equal(
 | |
|   LZW(false, [
 | |
|     84,
 | |
|     79,
 | |
|     66,
 | |
|     69,
 | |
|     79,
 | |
|     82,
 | |
|     78,
 | |
|     79,
 | |
|     84,
 | |
|     256,
 | |
|     258,
 | |
|     260,
 | |
|     265,
 | |
|     259,
 | |
|     261,
 | |
|     263
 | |
|   ]),
 | |
|   'TOBEORNOTTOBEORTOBEORNOT'
 | |
| );
 | |
| ```
 | |
| 
 | |
| `LZW(true, "0123456789")` should return `[48, 49, 50, 51, 52, 53, 54, 55, 56, 57]`.
 | |
| 
 | |
| ```js
 | |
| assert.deepEqual(LZW(true, '0123456789'), [
 | |
|   48,
 | |
|   49,
 | |
|   50,
 | |
|   51,
 | |
|   52,
 | |
|   53,
 | |
|   54,
 | |
|   55,
 | |
|   56,
 | |
|   57
 | |
| ]);
 | |
| ```
 | |
| 
 | |
| `LZW(false, [48, 49, 50, 51, 52, 53, 54, 55, 56, 57])` should return `"0123456789"`.
 | |
| 
 | |
| ```js
 | |
| assert.equal(
 | |
|   LZW(false, [48, 49, 50, 51, 52, 53, 54, 55, 56, 57]),
 | |
|   '0123456789'
 | |
| );
 | |
| ```
 | |
| 
 | |
| `LZW(true, "BABAABAAA")` should return `[66, 65, 256, 257, 65, 260]`.
 | |
| 
 | |
| ```js
 | |
| assert.deepEqual(LZW(true, 'BABAABAAA'), [66, 65, 256, 257, 65, 260]);
 | |
| ```
 | |
| 
 | |
| `LZW(false, [66, 65, 256, 257, 65, 260])` should return `"BABAABAAA"`.
 | |
| 
 | |
| ```js
 | |
| assert.equal(LZW(false, [66, 65, 256, 257, 65, 260]), 'BABAABAAA');
 | |
| ```
 | |
| 
 | |
| # --seed--
 | |
| 
 | |
| ## --seed-contents--
 | |
| 
 | |
| ```js
 | |
| function LZW (compressData, input) {
 | |
| 
 | |
| }
 | |
| ```
 | |
| 
 | |
| # --solutions--
 | |
| 
 | |
| ```js
 | |
| function LZW (compressData, input) {
 | |
|   function compress(uncompressed) {
 | |
|     // Build the dictionary.
 | |
|     var i,
 | |
|       dictionary = {},
 | |
|       c,
 | |
|       wc,
 | |
|       w = "",
 | |
|       result = [],
 | |
|       dictSize = 256;
 | |
|     for (i = 0; i < 256; i += 1) {
 | |
|       dictionary[String.fromCharCode(i)] = i;
 | |
|     }
 | |
| 
 | |
|     for (i = 0; i < uncompressed.length; i += 1) {
 | |
|       c = uncompressed.charAt(i);
 | |
|       wc = w + c;
 | |
|       //Do not use dictionary[wc] because javascript arrays
 | |
|       //will return values for array['pop'], array['push'] etc
 | |
|       // if (dictionary[wc]) {
 | |
|       if (dictionary.hasOwnProperty(wc)) {
 | |
|         w = wc;
 | |
|       } else {
 | |
|         result.push(dictionary[w]);
 | |
|         // Add wc to the dictionary.
 | |
|         dictionary[wc] = dictSize++;
 | |
|         w = String(c);
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     // Output the code for w.
 | |
|     if (w !== "") {
 | |
|       result.push(dictionary[w]);
 | |
|     }
 | |
|     return result;
 | |
|   }
 | |
| 
 | |
| 
 | |
|   function decompress(compressed) {
 | |
|     // Build the dictionary.
 | |
|     var i,
 | |
|       dictionary = [],
 | |
|       w,
 | |
|       result,
 | |
|       k,
 | |
|       entry = "",
 | |
|       dictSize = 256;
 | |
|     for (i = 0; i < 256; i += 1) {
 | |
|       dictionary[i] = String.fromCharCode(i);
 | |
|     }
 | |
| 
 | |
|     w = String.fromCharCode(compressed[0]);
 | |
|     result = w;
 | |
|     for (i = 1; i < compressed.length; i += 1) {
 | |
|       k = compressed[i];
 | |
|       if (dictionary[k]) {
 | |
|         entry = dictionary[k];
 | |
|       } else {
 | |
|         if (k === dictSize) {
 | |
|           entry = w + w.charAt(0);
 | |
|         } else {
 | |
|           return null;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       result += entry;
 | |
| 
 | |
|       // Add w+entry[0] to the dictionary.
 | |
|       dictionary[dictSize++] = w + entry.charAt(0);
 | |
| 
 | |
|       w = entry;
 | |
|     }
 | |
|     return result;
 | |
|   }
 | |
| 
 | |
|   if(compressData){
 | |
|     return compress(input)
 | |
|   }else{
 | |
|     return decompress(input)
 | |
|   }
 | |
| }
 | |
| ```
 |