Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
0

Fastest method of sorting an element into an array in ascending order? [ANSWERED]

Asked by 4 years ago
Edited 4 years ago

So this is more of a coding question than a lua question.

Let's say I have a pre-existing array of arbitrary size with repeating elements in ascending order:


local arr = {1, 1, 2, 3, 5, 8, 13, 21, 34}

I also have an arbitrary number that I want to sort into the above array:


local num = 4

What is the most efficient method of sorting that element into the array above? Note that the array could also be empty.

0
Are the elements in the array going to be sorted when they are inserted? MrLonely1221 701 — 4y
0
@MrLonely1221 Yes aquathorn321 858 — 4y
0
Is there a reason to not use table.sort()? xPolarium 1388 — 4y
0
@ xPolariumI don't want to sort the entire table, just one element. aquathorn321 858 — 4y
View all comments (5 more)
0
If the whole table is going to be sorted in the long run because you're inserting elements in a sorted fashion, why not just sort the table? MrLonely1221 701 — 4y
2
Your answer is very good @aquathorn321. The fastest way to place an element in the *sorted* array would be to binary search the location and inserting it, which you seem to do that in your recursive sort. You will not get a time complexity better than O(log n) for placing it might i add. Recall that sorting typically takes O(n log n). Therefore, that is the fastest way. AbstractionsReality 98 — 4y
1
there is no 'best sorting algorithm'   each have their pros and cons. if you have small arrays like this it wont matter anyway royaltoe 5144 — 4y
0
@AbstractionsReality Thanks I didn't know anything about sorting algorithms so I just came up with my own. I'm glad I found the one best suited for my purposes lol aquathorn321 858 — 4y
0
@royaltoe I guess I could've phrased my problem better. The table I provided was just an example. I plan for the table to take on a much larger and dynamic size, and I will be sorting multiple elements between frames. Instead of best I'm looking for the method which is most efficient on average, with efficiency measured by how long it takes the code to execute. aquathorn321 858 — 4y

2 answers

Log in to vote
1
Answered by 4 years ago

One easy way would be with an insert function that just cuts out an extra line of code each time you want to call. Insert the number into the table, then sort the table.

local tbl = {1, 1, 2, 3, 5, 8, 13, 21, 34}

function insert(num)
  table.insert(tbl, num)
  table.sort(tbl)
end

table.foreach(tbl, print)
insert(4)
insert(69)
insert(9)
table.foreach(tbl, print)
0
The problem with this solution, so far as I understand it, is that it is significantly more intensive to sort the entire table rather than just a single element. aquathorn321 858 — 4y
0
You're going to have to sort through the table up to the point where it is, so it's the same thing, just cutting off however many calls there are after the item you put in. Counting to the 10th slot rather than the 40th in a 50 index table. MrLonely1221 701 — 4y
Ad
Log in to vote
1
Answered by 4 years ago
Edited 4 years ago

So I ended up using a sort of iterative binary sort algorithm that best suits my needs. The function will compare the value to the median between the lowest and highest points on the table that the value could possibly be between. Every iteration the range is adjusted accordingly.

In the event that the number being sorted is compared to an equal value, the function will treat it as though the number being sorted is larger. This is intended, because I wrote this code to function inside my own 'Task Executer'. The Task Executer is a class which sequentially calls a list of functions, ordered by priority. The elements in the code below simulate that priority. I wanted consistent behavior in the event that several functions are sorted under the same priority, so the most recently sorted function will execute last.

I also replaced some library functions with my own code to improve efficiency. I plan on using my Task Executer for a fire spreading mechanic in my survival game, along with several GUI animations, so efficiency is very important to me since this code will get plenty of action.

CODE:

local arr = {1, 1, 2, 3, 5, 8, 13, 21, 34}

local function sort(value)

    local low = 0   --The lowest index the value is between.
    local high = #arr + 1   --The highest index the value is between.
    local pivot --The median element between low and high, rounded down.

    while high - low ~= 1 do    --When range is equal to 1, there are no more elements between low and high, so the value must fit in-between.

        pivot = (low + high)/2; pivot = pivot - pivot % 1   --Calculate the pivot. 

        if value < arr[pivot] then  --If value is less than element at index 'pivot', then set high to pivot
            high = pivot
        else    --If value is greater than or equal to element at index 'pivot', then set low to pivot. This will move the new value behind any recurring elements.
            low = pivot
        end     
    end

    for index = #arr + 1, high + 1, -1 do
        arr[index] = arr[index - 1] --Shift existing elements after index 'high' up one
    end; arr[high] = value  --Insert value at index 'high'

    print("SORTING VALUE " .. value .. " :", unpack(arr))

end

print("ORIGINAL:", unpack(arr))
sort(4)
sort(4)
sort(8)
sort(0)
sort(34)
sort(93)

OUTPUT:

ORIGINAL: 1 1 2 3 5 8 13 21 34
SORTING VALUE 4: 1 1 2 3 4 5 8 13 21 34
SORTING VALUE 4: 1 1 2 3 4 4 5 8 13 21 34
SORTING VALUE 8: 1 1 2 3 4 4 5 8 8 13 21 34
SORTING VALUE 0: 0 1 1 2 3 4 4 5 8 8 13 21 34
SORTING VALUE 34: 0 1 1 2 3 4 4 5 8 8 13 21 34 34
SORTING VALUE 93: 0 1 1 2 3 4 4 5 8 8 13 21 34 34 93

I think there's still some minimal room for improvement with optimizations, but this is probably good enough for now. Thanks for the help and resources guys!

1
Refer to this Lua implementation of Binary Search found here: https://rosettacode.org/wiki/Binary_search#Lua AbstractionsReality 98 — 4y
0
Although to find the midpoint i would write: local midpoint = low + (high - low) / 2; due to overflow issues with the typical midpoint = ( high - low )/2  AbstractionsReality 98 — 4y
0
Did you manage to get it working royaltoe 5144 — 4y
0
@royaltoe yes I'll edit my answer to reflect my solution aquathorn321 858 — 4y

Answer this question