JSFiddle - React, Tailwind, and code Playground

HTML

<div id="container"></div>

CSS

#container img {
  display: none;
}

#container .column {
  width: 50%;
  display: inline-block;
  vertical-align: top;
}

#container .column .image-padding {
  padding: 2px;
  position: relative;
}
#container .column .image-padding:after {
  content: attr(title);
  padding: 1px 5px;
  background: rgba(0, 0, 0, .8);
  position: absolute;
  top: 5px;
  left: 5px;
  color: white;
}
#container .column img {
  width: 100%;
  display: block;
}

JavaScript

function balance(numGroups, items, fetchValue){
		function delta(a, b){
			var da = a-avg, db = b-avg;
			return da*da + db*db;
		}
		
		function testAndSwitchItems(a,b){
			var valueA, valueB,
				lengthA = a.length, lengthB = b.length,
				indexA = lengthA, indexB = lengthB,
				bestDelta = delta(a.sum, b.sum);
				
			//test every item in this first column against every value in the second column
			for(var i = 0; i <= lengthA; ++i){
				//accessing a not available index of an Array may deoptimize this function
				//that's why i check the index before accessing the element.
				valueA = (i < lengthA && a[i] || nullElement).value;
				
				for(var j = 0; j <= lengthB; ++j){
					valueB = (j < lengthB && b[j] || nullElement).value;
					
					//test wether it would be an improvement to switch these items
					var d = delta(
						a.sum + valueB - valueA, 
						b.sum + valueA - valueB
					);
					
					//find the best combination
					if(d < bestDelta){
						indexA = i;
						indexB = j;
						bestDelta = d;
					}
				}
			}
		
			
			var elmA = indexA < lengthA && a[indexA], 
				elmB = indexB < lengthB && b[indexB],
				tmp;
		
			if(elmA && elmB){
				//switch items
				a[indexA] = elmB;
				b[indexB] = elmA;
				
			}else if(elmA){
				//move an item from a to b
				b.push(elmA);
				tmp = a.pop()
				if(elmA !== tmp)
					a[indexA] = tmp;
				
			}else if(elmB){
				//move an item from b to a
				a.push(elmB);
				tmp = b.pop()
				if(elmB !== tmp)
					b[indexB] = tmp;
				
			}else{
				//no switch would improve the result
				return false;
			}
			
			//compute the new sums per group
			valueA = (elmA || nullElement).value;
			valueB = (elmB || nullElement).value;
			a.sum += valueB - valueA;
			b.sum += valueA - valueB;
			return true;
		}
		
		function initGroupsAndReturnSum(sum, item, i){
			var value = fetchValue? fetchValue(item): item;
			
			//distribute the items
			if(i<numGroups){
				var group = groups[i] = [];
				group.sum =...