Chris
Chris

Reputation: 3129

Sorting array of objects dealing with empty objects

I am sorting an array of objects and having an issue keeping the empty objects in order, below will sort by SectionName

(() => {
  const items = [{
      ID: 20,
      SectionName: "Cabinet"
    },
    {
      ID: 0,
      SectionName: ""
    },
    {
      ID: 0,
      SectionName: ""
    },
    {
      ID: 20,
      SectionName: "Cabinet"
    },
    {
      ID: 2,
      SectionName: "Frame"
    },
    {
      ID: 0,
      SectionName: ""
    },
    {
      ID: 3,
      SectionName: "Alt"
    },
    {
      ID: 4,
      SectionName: "Upper"
    },
    {
      ID: 0,
      SectionName: ""
    },
    {
      ID: 0,
      SectionName: ""
    },
    {
      ID: 0,
      SectionName: ""
    },
    {
      ID: 5,
      SectionName: "Lower"
    }
  ];

  //items.forEach((e, i) => {
  //  console.log(e);
  //});

  // sort by name
  items.sort(function(a, b) {
    let nameA = a.SectionName.toUpperCase();
    let nameB = b.SectionName.toUpperCase();
    if (nameA < nameB) {
      return -1;
    }
    if (nameA > nameB) {
      return 1;
    }

    return 0;
  });

  console.table(items);

})();
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

but doesn't keep the empty objects in place before the sort, what I am trying to get it to sort like is

{ID: 3, SectionName: "Alt"},
{ID: 20, SectionName: "Cabinet"},
{ID: 0, SectionName: ""},
{ID: 0, SectionName: ""},
{ID: 20, SectionName: "Cabinet"},
{ID: 2, SectionName: "Frame"},
{ID: 0, SectionName: ""},
{ID: 5, SectionName: "Lower"},        
{ID: 0, SectionName: ""},
{ID: 0, SectionName: ""},
{ID: 0, SectionName: ""}  ,
{ID: 4, SectionName: "Upper"}

Upvotes: 1

Views: 794

Answers (2)

Nenad Vracar
Nenad Vracar

Reputation: 122037

You could just filter out those items where the SectionName is empty, sort that result and then insert back the empty ones into the sorted output.

const items = [{"ID":20,"SectionName":"Cabinet"},{"ID":0,"SectionName":""},{"ID":0,"SectionName":""},{"ID":20,"SectionName":"Cabinet"},{"ID":2,"SectionName":"Frame"},{"ID":0,"SectionName":""},{"ID":3,"SectionName":"Alt"},{"ID":4,"SectionName":"Upper"},{"ID":0,"SectionName":""},{"ID":0,"SectionName":""},{"ID":0,"SectionName":""},{"ID":5,"SectionName":"Lower"}]

const sorted = items
  .filter(({ SectionName }) => SectionName)
  .sort((a, b) => a.SectionName.localeCompare(b.SectionName))

items.forEach((e, i) => {
  if (!e.SectionName) sorted.splice(i, 0, e)
})

console.log(sorted)

Upvotes: 1

Nina Scholz
Nina Scholz

Reputation: 386560

This is an approach by using sort directly, but shaping the access with a Proxy for length and the indices.

const
    sort = (array, sortFn, filterFn = _ => true) => {
        const indices = [...array.keys()].filter(i => filterFn(array[i]));
        new Proxy(array, {
            get (target, prop) {
                if (isFinite(prop)) return target[indices[prop]];
                if (prop === 'length') return indices.length;
                return target[prop];
            },
            set (target, prop, receiver) {
                target[indices[prop]] = receiver;
                return true;
            }
        })
        .sort(sortFn);

        return array;
    },
    items = [{ ID: 20, SectionName: "Cabinet" }, { ID: 0, SectionName: "" }, { ID: 0, SectionName: "" }, { ID: 20, SectionName: "Cabinet" }, { ID: 2, SectionName: "Frame" }, { ID: 0, SectionName: "" }, { ID: 3, SectionName: "Alt" }, { ID: 4, SectionName: "Upper" }, { ID: 0, SectionName: "" }, { ID: 0, SectionName: "" }, { ID: 0, SectionName: "" }, { ID: 5, SectionName: "Lower" }];
    
console.log(...sort(
    items,
    (a, b) => a.SectionName.localeCompare(b.SectionName),
    ({ SectionName }) => SectionName
));
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 1

Related Questions