Skip to content

Instantly share code, notes, and snippets.

@cferdinandi
Created December 10, 2020 15:01
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cferdinandi/85592ee3387961ce3d4c3bebd3170bbb to your computer and use it in GitHub Desktop.
Save cferdinandi/85592ee3387961ce3d4c3bebd3170bbb to your computer and use it in GitHub Desktop.

Gandalf Good Gray Saruman Bad White Radagast Awesome Green Alatar Who? Blue

Gandalf - Good Saruman - Bad Radagast - Awesome Alatar - Who?

<!DOCTYPE html>
<html>
<head>
<title>Sorter</title>
<style type="text/css">
body {
margin: 0 auto;
max-width: 40em;
width: 88%;
}
/**
* Form Styles
*/
form,
textarea {
margin-bottom: 1em;
}
label,
textarea {
display: block;
width: 100%;
}
label {
font-weight: bold;
}
textarea {
min-height: 12em;
}
#sorted {
white-space: pre-wrap;
}
</style>
</head>
<body>
<h1>Sorter App</h1>
<form id="sorter">
<label for="sort">Stuff to Sort</label>
<textarea id="sort"></textarea>
<button>Sort My Stuff</button>
</form>
<div id="sorted" aria-live="polite"></div>
<script>
// Variables
var sorter = document.querySelector('#sorter');
var sort = document.querySelector('#sort');
var sorted = document.querySelector('#sorted');
/**
* Handle form submissions
* @param {Event} event The event object
*/
var submitHandler = function (event) {
// Stop the form from submitting
event.preventDefault();
// Convert items to an array
var items = sort.value.split('\n');
// Sort alphabetically
items.sort();
// Update the UI
sorted.textContent = items.join('\n');
};
// Listen for form submissions
sorter.addEventListener('submit', submitHandler);
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>Sorter</title>
<style type="text/css">
body {
margin: 0 auto;
max-width: 40em;
width: 88%;
}
/**
* Form Styles
*/
form,
textarea,
input {
margin-bottom: 1em;
}
label,
textarea,
input {
display: block;
width: 100%;
}
label {
font-weight: bold;
}
textarea {
min-height: 12em;
}
#sorted {
white-space: pre-wrap;
}
</style>
</head>
<body>
<h1>Sorter App</h1>
<form id="sorter">
<label for="sort">Stuff to Sort</label>
<textarea id="sort"></textarea>
<label for="remove">Lines to Remove (comma separated)</label>
<input type="tel" id="remove">
<button>Sort My Stuff</button>
</form>
<div id="sorted" aria-live="polite"></div>
<script>
// Variables
var sorter = document.querySelector('#sorter');
var sort = document.querySelector('#sort');
var sorted = document.querySelector('#sorted');
var remove = document.querySelector('#remove');
/**
* If items should be removed, remove them
* @param {Array} items The items to sort
* @return {Array} The items with lines removed
*/
var removeItems = function (items) {
// If nothing should be removed, return as-is
if (!remove.value.length) return item;
// Get the lines to remove
// ex. [2, 3]
var lines = remove.value.split(',').map(function (num) {
return parseInt(num.trim(), 10) - 1;
});
// Create a new array, with lines removed
return items.filter(function (item, index) {
// Skip the first item
// if (index === 0) return true;
// Check if line should be removed
var removeIt = lines.filter(function (line) {
return line % index === 0;
}).length;
console.log(item, (index), !!removeIt);
// If line should be removed, exclude it
// Otherwise, keep it in the array
return removeIt ? false : true;
});
};
/**
* Handle form submissions
* @param {Event} event The event object
*/
var submitHandler = function (event) {
// Stop the form from submitting
event.preventDefault();
// Convert items to an array
var items = sort.value.split('\n');
items = removeItems(items);
// Sort alphabetically
items.sort();
// Update the UI
sorted.textContent = items.join('\n');
};
// Listen for form submissions
sorter.addEventListener('submit', submitHandler);
</script>
</body>
</html>
@SeizeDub
Copy link

SeizeDub commented Dec 11, 2020

Instead of using line-1, you should use index+1, or else it will screw up with the modulo (result always equals to 0 when you divide by 1).
Also I think using the function array.every() is quite usefull in this case :

var removeItems = function (items) {
if (!remove.value.length) return items;
var lines = remove.value.split(',').map(num => parseInt(num.trim(), 10));
return items.filter((item, index) => lines.every(line => (index + 1) % line !== 0));
};

I love what you do Chris, keep it up please ! :D

@begroff
Copy link

begroff commented Dec 12, 2020

How about this solution? For removeIt, I check to see if the current index is equal to the line to be removed.

If you had a list of 4 lines and wanted to remove lines 3 and 4, the lines array would be [2,3]. When the index of the items array being iterated is 2 that would correlate to the 3rd item, whose value in the lines array is 2.

var removeItems = function (items) {

    // If nothing should be removed, return as-is
    if (!remove.value.length) return items;

    // Get the lines to remove
    // ex. [2, 3]
    var lines = remove.value.split(',').map(function (num) {
        return parseInt(num.trim(), 10) - 1;
    });

    // Create a new array, with lines removed
    return items.filter(function (item, index) {
        // Check if line should be removed
        var removeIt = lines.filter(function (line) {
            if (index === line) {
                return true;
            }
        }).length

        // If line should be removed, exclude it
        // Otherwise, keep it in the array
        return removeIt ? false : true;
    });
};

@dfkaye
Copy link

dfkaye commented Dec 12, 2020

@cferdinandi - 3 small changes make it work.

Line 75

  • trim the remove value (minor)
  • should add an s to item
if (!remove.value.trim().length) return items; // not this -> return item;

creating lines array

Replace map() with a filter() to return only valid indexes for an array. The map() returns -1 if we enter 0 in the remove field, e.g.

var lines = remove.value.split(',').filter(function (num) {
    var index = parseInt(num.trim(), 10) - 1
    
    return index >= 0 // return true if index is valid for an array 0,1,2...
});	

filtering lines array

  • Should check equality, not divisibility (because 8 matches 2,4, and 8).
  • Use the +(value) trick to coerce line to a number. index doesn't really need it, but it makes clear we are checking strict numeric equality.
  • And finally, to remove Gandalf we need to decrement the line by 1 to get 0.
var removeIt = lines.filter(function (line) { 					
    return +(line - 1) === +(index); // not this -> return line % index === 0;
}).length;

Test input

  • Use 1,2,3,4,5,6,7,8,9,10,11 to verify that only Blue remains.
  • Use 2,3,4,5,6,7,8,9,10,11,12 to verify that only Gandalf remains.

Voilà!

@cferdinandi
Copy link
Author

One thing I think I didn't make clear: I don't want to have to enter every single line to remove. Ideally, I would be able to tell the script to remove every 2nd and 3rd line in a three line group and have it figure that out.

@begroff
Copy link

begroff commented Dec 12, 2020

With the original advanced data what would be the expected result if you passed 2,3 to remove?

@cferdinandi
Copy link
Author

@begroff - great question!

Input

Gandalf
Good
Gray
Saruman
Bad
White
Radagast
Awesome
Green
Alatar
Who?
Blue

Output

Gandalf
Saruman
Radagast
Alatar

@SeizeDub
Copy link

In that case you'll have to somehow tell the script that the lines are grouped by 3. I can't really see an alternative.

@cferdinandi
Copy link
Author

That’s what I was trying to get at with the remainder operator

@svivian
Copy link

svivian commented Dec 13, 2020

Pretty sure your problem is you have the modulo backwards. It should be (index+1) % line === 0 (using your original version where you don’t do -1 from the parseInt). It’s the index that you want to check, i.e. take index 2 and check it against 2 and 3.

Personally I would’ve looped through the ‘lines’ array instead of a sub filter, that way you can return true as soon as you find that the line needs to be removed.

PS your first problem earlier in the video with the new line was because you put /n instead of \n :)

@cferdinandi
Copy link
Author

Personally I would’ve looped through the ‘lines’ array instead of a sub filter, that way you can return true as soon as you find that the line needs to be removed.

I mentioned this in one of the comments, but I don't want to match exactly line 2, line 3, etc. I want to match every second or every third line, which is a bit different.

your first problem earlier in the video with the new line was because you put /n instead of \n

Yea, caught that a bit later in the video 😉

@svivian
Copy link

svivian commented Dec 13, 2020

I don't want to match exactly line 2, line 3, etc. I want to match every second or every third line, which is a bit different.

I was aware of that, and technically my solution does that. But removing "every second line" would remove lines 2, 4, 6 and so on. What you actually want is to remove every third line, but starting at line 2. And again starting at line 3. So SeizeDub is right about the missing 'group' parameter. This code works:

// Create a new array, with lines removed
return items.filter(function (item, index) {

	for (var i = 0; i < lines.length; i++) {
		// Check if line should be removed
		if (index % 3 === (lines[i] - 1))
			return false;
	}

	// If we got here, line should not be removed
	return true;
	
});

The 3 in index % 3 would need to be replaced by another input box.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment