Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

array.sort for multiple members and/or stable sort algorithm #405

Open
InspiringCode opened this issue Jan 25, 2022 · 1 comment
Open

array.sort for multiple members and/or stable sort algorithm #405

InspiringCode opened this issue Jan 25, 2022 · 1 comment

Comments

@InspiringCode
Copy link

First of all, this is really an AWESOME project!

I have the problem, that I have to sort an array by two members, first bei DateAdded and then by Name (both properties of the Member class). Since we can only pass a single member to array.sort, my first idea was to use

sorted = members | array.sort "Name" | array.sort "DateAdded"

BUT this doesn't work, since the internally used List<T>.Sort does NOT use a stable sorting algorithm (see docs).

The solution would be to use a stable sorting algorithm like the one used by Enumberable.OrderBy.

One workaround would be to override the bulitin sort function with:

private class CustomBuiltinFunctions : BuiltinFunctions {
    public CustomBuiltinFunctions() {
        ArrayFunctions array = (ArrayFunctions)this["array"];
        array.Remove("sort");
        array.Import("sort", new Func<TemplateContext, SourceSpan, object, string, IEnumerable>(Sort));
    }

    private static IEnumerable Sort(TemplateContext context, SourceSpan span, object list, string? member = null) {
        if (list == null) {
            return new ScriptRange();
        }

        IEnumerable? enumerable = list as IEnumerable;

        if (enumerable == null)
            return new ScriptArray(1) { list };

        var items = enumerable.Cast<object>();
        if (!items.Any())
            return new ScriptArray();

        if (string.IsNullOrEmpty(member)) {
            items = items.OrderBy(x => x);
        } else {
            items = items.OrderBy(target => {
                IObjectAccessor accessor = context.GetMemberAccessor(target);

                if (!accessor.TryGetValue(context, span, target, member, out object value)) {
                    context.TryGetMember?.Invoke(context, span, target, member, out value);
                }

                return value;
            });
        }

        return new ScriptArray(items);
    }
}

But in my opinion it would be of great value to use a stable sort algorithm by default. Since this wouldn't be a breaking change I would really welcome to see this fixed in the next release. What do you think?

Even better would be to support sorting by multiple members, which would be much more efficient and performant.

@xoofx
Copy link
Member

xoofx commented Jan 28, 2022

But in my opinion it would be of great value to use a stable sort algorithm by default. Since this wouldn't be a breaking change I would really welcome to see this fixed in the next release. What do you think?

Yep, makes sense, PR welcome.

Even better would be to support sorting by multiple members, which would be much more efficient and performant.

Possible, more complicated to bring, up to you 😉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants