JSFiddle - React, Tailwind, and code Playground

by Tomalak

HTML

<script src="//cdnjs.cloudflare.com/ajax/libs/linq.js/2.2.0.2/linq.min.js "></script>
<h3>Before</h3>
<pre id="before"></pre>
<hr>
<h3>After</h3>
<pre id="after"></pre>

JavaScript

// Enumerable, definition => Enumerable
function applyOrder(items, definition) {
    var i, prop, prefix, suffix, orderFunc;
    if (!items) return;
    if (!definition) return items;
    for (i = 0; i < definition.length; i++) {
        // definition[i] is either "propertyName" or "propertyName DESC"
        prop = (definition[i] + " ").split(" ");
        prefix = i === 0 ? "OrderBy" : "ThenBy";
        suffix = prop[1].toUpperCase() === "DESC" ? "Descending" : "";
        orderFunc = prefix + suffix;
        items = items[orderFunc]("$." + prop[0]);
    }
    return items;
}

// Enumerable, definition => Enumerable
function applyGroup(items, definition) {
    if (!items) return;
    if (!definition) return items;
    items = applyOrder(items, definition.order);
    if (!definition.group) return items;
    return items.GroupBy("$." + definition.group, "", function (key, e) {
        return {
            group: definition.group,
            key: key,
            items: applyGroup(e, definition.then).ToArray()
        };
    });
}

// Array, definition => Array
function applyStructure(items, definition) {
    if (!items) return;
    if (!definition) return items;
    return applyGroup(Enumerable.From(items), definition).ToArray();
}

// list of items
var companies = [{
        country: "Mexico",
        city: "México D.F.",
        companyName: "Ana Trujillo ..."
    }, {
        country: "Mexico",
        city: "México D.F.",
        companyName: "Antonio Moreno ..."
    }, {
        country: "Mexico",
        city: "México D.F.",
        companyName: "Centro Comercial ..."
    }, {
        country: "USA",
        city: "Charlotte",
        companyName: "Bank of America"
    }];

var result = applyStructure(companies, {
    group: "country",
    order: ["country"],
    then: {
        group: "city",
        order: ["city"],
        then: {
            order: [
                "companyName DESC"
                /* note that you can add more order clauses per...