3

I want something that would result in this

[{
    firstName: "Sam",
    lastName: "Smith"
}, {
    firstName: "Sam",
    lastName: "Doe"
}, {
    firstName: "Sam",
    lastName: "Doe"
}, {
    firstName: "Sam",
    lastName: "Joe"
}]

Being something like this, with the exception of the number of columns to group with which is not fixed and the order of the columns as well

[{
    "Sam": [{
        "Smith": [{
            firstName: "Sam",
            lastName: "Smith"
        }]
    }, {
        "Doe": [{
            firstName: "Sam",
            lastName: "Doe"
        }, {
            firstName: "Sam",
            lastName: "Doe"
        }]
    }, {
        "Joe": [{
            firstName: "Sam",
            lastName: "Joe"
        }]
    }]
}]

I want to be able to build something like the following photo demonstrates

enter image description here

I tried several times but i can't get a grasp on it, please help me :).

Ibrahim Ahmed
  • 2,295
  • 4
  • 21
  • 35

1 Answers1

2

I propose a different output structure. Your structure seems convenient at first glance, but in further processing it will prove unnecessarily difficult to handle.

I would suggest this generic structure:

[
  {
    key: "group 1",
    items: [{
      key: "group 1.1",
      items: [ {}, {}, {} ]
    }, {
      key: "group 1.2",
      items: [ {}, {} ]
    }]
  }, {
    key: "group 2",
    items: [{
      key: "group 2.1",
      items: [ {}, {}, [}, {} ]
    }, {
      key: "group 2.2",
      items: [ {} ]
    }]
  }
]

You can create a structure like this relatively easily:

var grouped = Enumerable.From(input).GroupBy("$.firstName", "", function(key, e) {
    return {
        key: key,
        items: e.GroupBy("$.lastName", "", function (key, e) {
            return {
                key: key,
                items: e.ToArray()
            };
        }).ToArray()
    };
}).ToArray();

when applied to this input:

var input = [{
    firstName: "Sam",
    lastName: "Smith"
}, {
    firstName: "Sam",
    lastName: "Doe"
}, {
    firstName: "Sam",
    lastName: "Doe"
}, {
    firstName: "Sam",
    lastName: "Joe"
},{
    firstName: "John",
    lastName: "Joe"
}];

results in

[
  {
    "key": "Sam",
    "items": [
      {
        "key": "Smith",
        "items": [
          {
            "firstName": "Sam",
            "lastName": "Smith"
          }
        ]
      },
      {
        "key": "Doe",
        "items": [
          {
            "firstName": "Sam",
            "lastName": "Doe"
          },
          {
            "firstName": "Sam",
            "lastName": "Doe"
          }
        ]
      },
      {
        "key": "Joe",
        "items": [
          {
            "firstName": "Sam",
            "lastName": "Joe"
          }
        ]
      }
    ]
  },
  {
    "key": "John",
    "items": [
      {
        "key": "Joe",
        "items": [
          {
            "firstName": "John",
            "lastName": "Joe"
          }
        ]
      }
    ]
  }
]

Edit: To allow dynamically configurable grouping and ordering, a more advanced approach must be taken:

// 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();
}

used like this:

var result = applyStructure(companies, {
    group: "country",
    order: ["country"],
    then: {
        group: "city",
        order: ["city"],
        then: {
            order: ["companyName DESC"]
        }
    }
});

live at: http://jsfiddle.net/Tomalak/xth6ayuo/

Tomalak
  • 332,285
  • 67
  • 532
  • 628
  • That did work but what if i don't know how many columns i want to group by, This is my main concern. – Ibrahim Ahmed Jan 03 '15 at 15:01
  • Like firstName then lastName then country or any other order and columns – Ibrahim Ahmed Jan 03 '15 at 15:31
  • 1
    That really quite a change from your original question. – Tomalak Jan 03 '15 at 17:58
  • I would assume sorry if i did not make my self clear the first time i'll edit the question :). – Ibrahim Ahmed Jan 03 '15 at 20:23
  • 1
    Changing your requirements substantially in mid-flight is not a nice thing to do. It basically communicates *"Sorry, I just wasted your time because I did not really think about what I needed up-front, but hey, at least it's been your time, not mine"*. That's especially true for a question that did not contain any code to begin with. – Tomalak Jan 03 '15 at 21:42
  • Sir i do appreciate the time you took to answer my question and i do apologize if i did not make that clear,so again you've been more than generous with what you offered, I'm grateful for that and sorry if i wasted your time, I assure you that was not intended, My question was simply not clear, my mistake i apologize. – Ibrahim Ahmed Jan 03 '15 at 22:03
  • 1
    I am not upset or anything, I just wanted to make that clear for the future. Think half an hour longer about your questions in the future, you owe it to the people that help you for free. – Tomalak Jan 03 '15 at 22:17
  • Your point is valid, I hope you find it in your heart to accept my sincere apology, which i also owe to the stack community. – Ibrahim Ahmed Jan 03 '15 at 22:19
  • 1
    So, that being said, here is pretty much everything you wanted, and something extra. http://jsfiddle.net/Tomalak/xth6ayuo/. – Tomalak Jan 03 '15 at 22:22
  • Please accept my vehement protestations of gratitude, I stand weak before your generosity. – Ibrahim Ahmed Jan 03 '15 at 22:35
  • 1
    Oh come on. I said I wasn't upset or anything. In the end it was an interesting problem to solve. If you take the time to work through and understand the solution, that's repayment enough. – Tomalak Jan 03 '15 at 22:38