0

I have an object that looks like this:

var obj = {
  "array1": [
    {"label": "something1", "ref": "option2a"},
    {"label": "something2", "ref": "option2b"},
    {"label": "something3", "ref": "option2a"},
    {"label": "something4", "ref": "option2a"},
    {"label": "something5 is the longest", "ref": "option2a"}
  ],
  array2: [
    "arrayItem1",
    "array Item 2"
  ]
}

This object contains arrays of objects and arrays of strings. I would like to traverse through each object that has a label and return the longest label. In the previous example, the expected output id:

"something5 is the longest".

I have tried the following:

function getLongest(object, key) {
  return Object.values(object).reduce((l, v) => {
    if (object.hasOwnProperty(key)) {
      if (key in v)
        return Math.max(l, v[key].length);
      if (v && typeof v === 'object')
        return Math.max(l, getLongest(v, key));
      return l;
    }
  }, 0);
}

However this gives me an error because it cannot find the property label for the items in array2.

2
  • @Mandalina, are 'array1' and 'array2' to be compared against each other? Separately? Or only arrays with "label" keys (such as 'array1')? Commented Jan 11, 2019 at 19:01
  • 1
    Hey @SunnyPatel yes I only need to get arrays with "label" keys; like array1. Commented Jan 11, 2019 at 19:07

3 Answers 3

1

Here you have one approach that used anidated reduce() methods over the Object.Values():

var obj = {
    "array1": [
        {"label": "something1", "ref": "option2a"},
        {"label": "something2", "ref": "option2b"},
        {"label": "something3", "ref": "option2ahgf"},
        {"label": "something4", "ref": "option2a"},
        {"label": "I'm not the longest", "ref": "option2a"}
    ],
    array2: [
        "arrayItem1",
        {"label": "something5 is the longest", "ref": "option2a"},
        "array Item 2"
    ],
    array3: [
        {"label": "somethingX", "ref": "option2X"},
        {"label": "somethingY", "ref": "option2Y"}
    ]
}

const getLongest = (obj, key) =>
{
    let r = Object.values(obj).reduce((res, curr) =>
    {
        if (!Array.isArray(curr))
            return res;

        let newMax = curr.reduce(
            (r, c) => c[[key]] && (c[[key]].length > r.length) ? c[[key]] : r,
            ""
        );

        res = newMax.length > res.length ? newMax : res;
        return res;

    }, "");

    return r;
}

console.log(getLongest(obj, "label"));
console.log(getLongest(obj, "ref"));

Sign up to request clarification or add additional context in comments.

1 Comment

I just updated it to wrap the logic inside a function and generalize it a little more.
0

Example:

// object declaration
var obj = {
  "array1": [{
      "label": "something1",
      "ref": "option2a"
    },
    {
      "label": "something2",
      "ref": "option2b"
    },
    {
      "label": "something3",
      "ref": "option2a"
    },
    {
      "label": "something4",
      "ref": "option2a"
    },
    {
      "label": "something5 is the longest",
      "ref": "option2a"
    }
  ],
  array2: [
    "arrayItem1",
    "array Item 2"
  ]
};

// iterate over all items in obj
for (var propertyName in obj) {
  // if the item is an object and is an array
  if (typeof obj[propertyName] === 'object' && Array.isArray(obj[propertyName])) {
    // if the array has at least one item and a property of label
    if (obj[propertyName].length > 0 && typeof obj[propertyName][0].label !== 'undefined') {
      // sort the array by length of label
      obj[propertyName].sort((a,b) => (a.label.length < b.label.length) ? 1 : ((b.label.length < a.label.length) ? -1 : 0));
      // console.log print the longest label
      console.log('longest label name:', obj[propertyName][0].label);
    }
  }
}

// output the whole obj
console.log(obj);

3 Comments

I don't think OP literally wants to sort them. Just get back the label with longest value.
` I would like to sort through each object that has a label and return the label that is the longest. In this case it would return "something5 is the longest" ` @SunnyPatel
"sort through each" can be considered as "iterate through each". As in "sorting through papers", you would go "through" them.
0

Since you mentioned jQuery, I've included a solution that uses jQuery.map to iterate through your outer object and array.reduce to yield only one result from each array value inside obj.

var obj = {
  "array1": [{
      "label": "something1",
      "ref": "option2a"
    },
    {
      "label": "something2",
      "ref": "option2b"
    },
    {
      "label": "something3",
      "ref": "option2a"
    },
    {
      "label": "something4",
      "ref": "option2a"
    },
    {
      "label": "something5 is the longest",
      "ref": "option2a"
    }
  ],
  array2: [
    "arrayItem1",
    "array Item 2"
  ]
}
function getLongest(curr, next) {
  return !Object.keys(next).includes("label") || curr.label.length > next.label.length ? curr : next;
}

var reduced = $.map(obj, item => item.reduce(getLongest, {"label": ""}))
console.log(reduced);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

This basically iterates through each key's value inside obj and reduces the array down to a single object that has a label with the longest label, if it even has a label key. If it does not, it returns a default object without a label and works with arrays with mixed objects/strings.

So it returns an object with the matching keys of obj.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.