4

I has a multi dimensional array. It can have more than one array in itself. Sometimes maybe 5 or 6. Now I want to get the largest array from my multi dimensional array by using array size. I don't know how to achieve this. Hence i'm posting here. Thanks in advance.

For example:

[["a", "b", "c"], ["d", "e", "f", "g", "h", "i", "j"]]

1
  • Can you show your nested array. Commented Jan 21, 2017 at 9:16

3 Answers 3

13

If you are looking for the longest subarray within the given array then you can simply use max(by:) with a comparison using the array count:

let a = [["a", "b", "c"], ["d", "e", "f", "g", "h", "i", "j"], ["k"]]

let longestSubArray = a.max(by: { $0.count < $1.count })!

print(longestSubArray)
// ["d", "e", "f", "g", "h", "i", "j"]

Here I have assumed that a is not empty, otherwise max(by:) will return nil. If that can happen, use optional binding:

if let longestSubArray = a.max(by: { $0.count < $1.count }) {
    print(longestSubArray)
} else {
    print("a is empty")
}

Remark: Array is a RandomAccessCollection and therefore getting its count is a O(1) operation.

If you need both the longest element and its index in the containing array then you can apply the above to a.enumerated():

if let (idx, longest) = a.enumerated().max(by: { $0.element.count < $1.element.count }) {
    print("longest subarray", longest)
    print("at index", idx)
}

If there is more than one subarray with the maximal length then the above solutions will return one of them. @dfri's answer shows how to get all subarrays with the maximal length.

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

Comments

3

Maybe the most obvious (not the shortest) way:

I am just looping through the array and checking the size of the array inside

let anArray = [["Hello", "This", "is"], ["Hello", "This", "is", "a", "5"], ["Hello", "This", "is", "a", "6", "!"]])

var max = 0

for array in anArray
{
    if array.count > max
    {
        max = array.count
    }
}

print(max)

You could use an array of AnyObject or something else instead of string for your own purpose

EDIT

Based on your comments, just have the following update:

I made this function:

func getLongestArray(anArr:[[String]]) -> [String]
{
    var maxArr = [String]()

    for array in anArr
    {
        if(array.count > maxArr.count)
        {
            maxArr = array
        }
    }

    return maxArr
}

And then where appropriate, make this call

let anArray = [["Hello", "This", "is"], ["Hello", "This", "is", "a", "5"], ["Hello", "This", "is", "a", "6", "!"]]

print(getLongestArray(anArr: anArray))

This should return the longest array although assuming you at least have an array of size > 0

8 Comments

this only gets the size of the array. I need the longest array. anyway thank you.
how do you define the longest array ? The array with the most strings in it or the total character count inside the array ? I did the former
your code just return only the max number - but the requested answer was the array itself
I you happen to encounter a huge array where all subarrays happens to be somewhat sorted in increasing order w.r.t. to count, the solution above will use a huge amount of unnecessary wasteful array assignments (maxArr = array). A more sensible approach would be to simply track the index of the longest subarray, and after exiting the for loop, simply return the subarray corresponding to the "max" index.
@dfri: I don't think that the assignment is a problem due to the copy-on-write implementation of arrays. The loop variable array is already a copy of the array element, as are $0, $1 in my a.max(by: { $0.count < $1.count }) or $0 in your second solution.
|
2

The max(by:) approach used in @MartinR:s answer is the fit for purpose solution here, but (as I commonly write :), for the joy of alternatives, you could also "manually" fold over the indices over your array to find the index which corresponds to the longest sub-array (maximum .count):

let arr = [["a", "b", "c"], ["d", "e", "f", "g", "h", "i", "j"]]

if arr.count > 0 {
    let longestSubArray = arr[
        arr.indices.reduce(0) { arr[$1].count > arr[$0].count ? $1 : $0 } // (*)
    ]
    print(longestSubArray) // ["d", "e", "f", "g", "h", "i", "j"]
}

/* (*) Alternatively:
arr.indices.lazy.map { arr[$0].count }.max() ?? 0 */

In case you'd like to find the subset of subarrays that have the largest count (which may not be a single one), you could use a similar approach combined with filter:

// two longest subarrays with same count
let arr = [["a", "b", "c"],
           ["d", "e", "f", "g", "h", "i", "j"],
           ["k", "l", "m", "n", "o", "p", "q"]]

let maxSubArrayCount = arr.lazy.map { $0.count }.max() // thanks @muescha (+)
let longestSubArrays = arr.filter { $0.count == maxSubArrayCount }
print(longestSubArrays) /* [["d", "e", "f", "g", "h", "i", "j"], 
                            ["k", "l", "m", "n", "o", "p", "q"]] */

/* (+) Alternatively:
let maxSubArrayCount = arr.reduce(0) { $1.count > $0 ? $1.count : $0 } */

7 Comments

your first code snipped is broken with this array let arr = [["a", "b", "c"], ["2"], ["d", "e", "f", "g", "h", "i", "j"]] it returns ["2"]
shorter: let maxSubArrayCount = arr.map{$0.count}.max()
@muesha it is shorter shorter, but will use two passes over the array (as compared to the single pass of the reduce approach). Possibly arr.lazy.map { $0.count }.max() would result in only a single pass though.
but the reduce need to call the count twice for the array?
I believe (the slightly modified version of your proposal) arr.lazy.map { $0.count }.max() is the best approach here, in the end; imo it has slightly better semantics than the reduce approach. Thanks for the feedback!
|

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.