{"id":23983770,"url":"https://github.com/nenonaninu/nthitemutils","last_synced_at":"2026-06-12T06:31:00.529Z","repository":{"id":103979930,"uuid":"290523044","full_name":"nenoNaninu/NthItemUtils","owner":"nenoNaninu","description":"Script to get the nth smallest/largest item. Inspired by std::nth_element.","archived":false,"fork":false,"pushed_at":"2020-08-29T17:29:57.000Z","size":26,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-07T12:37:39.613Z","etag":null,"topics":["csharp","nthelement","quickselect"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nenoNaninu.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-08-26T14:43:39.000Z","updated_at":"2020-12-22T09:27:20.000Z","dependencies_parsed_at":"2024-06-21T11:45:12.551Z","dependency_job_id":null,"html_url":"https://github.com/nenoNaninu/NthItemUtils","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nenoNaninu%2FNthItemUtils","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nenoNaninu%2FNthItemUtils/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nenoNaninu%2FNthItemUtils/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nenoNaninu%2FNthItemUtils/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nenoNaninu","download_url":"https://codeload.github.com/nenoNaninu/NthItemUtils/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240578788,"owners_count":19823689,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["csharp","nthelement","quickselect"],"created_at":"2025-01-07T12:28:41.799Z","updated_at":"2025-11-18T06:03:24.065Z","avatar_url":"https://github.com/nenoNaninu.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# NthItemUtils\n\nA library for getting the nth smallest value, the nth largest value, etc. from a randomly accessible data structure like `Span\u003cT\u003e`,`ReadOnlySpan\u003cT\u003e`, `IReadOnlyList\u003cT\u003e`.\nInternally, it uses QuickSelect as well as C++ `std::nth_element()`, so the average performance is O(n).\n\nThe source code consists of **only one file**, so you can easily use it by copy and past.\n\n[source code](https://github.com/nenoNaninu/NthItemUtils/blob/master/NthItemUtils/NthItemUtils.cs)\n\nor [nuget](https://www.nuget.org/packages/NthItemUtils/).\n```\ndotnet add package NthItemUtils\n```\n\n# API\nAPI is defined as an extension method of `Span\u003cT\u003e`, `ReadOnlySpan\u003cT\u003e`, and `IReadOnlyList\u003cT\u003e`.\nThe range of n is between 0 and source.Length - 1.\nAll return value types are `struct ItemWithIndex\u003cT\u003e{ T Item; int index }`.\n```cs\nNthSmallest\u003cT\u003e(this Span\u003cT\u003e source, int n)\nNthSmallest\u003cT\u003e(this Span\u003cT\u003e source, int n, Comparer\u003cT\u003e comparer)\n\nNthLargest\u003cT\u003e(this Span\u003cT\u003e source, int n)\nNthLargest\u003cT\u003e(this Span\u003cT\u003e source, int n, Comparer\u003cT\u003e comparer)\n\nMaxWithIndex\u003cT\u003e(this Span\u003cT\u003e source)\nMaxWithIndex\u003cT\u003e(this Span\u003cT\u003e source, Comparer\u003cT\u003e comparer)\n\nMinWithIndex\u003cT\u003e(this Span\u003cT\u003e source)\nMinWithIndex\u003cT\u003e(this Span\u003cT\u003e source, Comparer\u003cT\u003e comparer)\n```\n\nSince QuickSelect is used internally, this is also published as an API.\n\n\n```cs\npublic static class QuickSelect\n{\n    public static void Iota(Span\u003cint\u003e indices);\n    \n    public static void Execute\u003cT\u003e(ReadOnlySpan\u003cT\u003e source, Span\u003cint\u003e indices, int n);\n    public static void Execute\u003cT\u003e(ReadOnlySpan\u003cT\u003e source, Span\u003cint\u003e indices, int n, Comparer\u003cT\u003e comparer);\n    \n    public static void Execute\u003cT\u003e(IReadOnlyList\u003cT\u003e source, Span\u003cint\u003e indices, int n);\n    public static void Execute\u003cT\u003e(IReadOnlyList\u003cT\u003e source, Span\u003cint\u003e indices, int n, Comparer\u003cT\u003e comparer);\n}\n\n```\n# Example\nExtension Method.\n```cs\nvar random = new Random();\nvar randomSource = Enumerable.Range(0, 200).Select(_ =\u003e random.NextDouble() * 50).ToArray();\n\nvar order = randomSource.OrderBy(x =\u003e x).ToArray();\n\nint n = random.Next(200);\n\nAssert.IsTrue(order[n] == randomSource.AsSpan().NthSmallest(n).Item); // always true.\n```\n\nQuickSelect\n\n```cs\nReadOnlySpan\u003cint\u003e source = new int[] { 4, 4, 8, 1, 2, 5, 4, 4, 4, 6, 7, 3 }.AsSpan();\nvar pool = ArrayPool\u003cint\u003e.Shared.Rent(source.Length);\nvar indices = pool.AsSpan(0, source.Length);\n\nint n = 6;\n\nQuickSelect.Iota(indices);\nQuickSelect.Execute(source, indices, n);\n\nvar pivot = source[indices[n]];\nfor (int i = 0; i \u003c n; i++)\n{\n    var result = Comparer\u003cdouble\u003e.Default.Compare(source[indices[i]], pivot);\n\n    Assert.IsTrue(result \u003c= 0); // always true.\n}\n\nfor (int i = n + 1; i \u003c source.Length; i++)\n{\n    var result = Comparer\u003cdouble\u003e.Default.Compare(source[indices[i]], pivot);\n\n    Assert.IsTrue(0 \u003c= result); // always true.\n}\n\nArrayPool\u003cint\u003e.Shared.Return(pool);\n```\nGet items in some range\n```cs\nReadOnlySpan\u003cint\u003e randomSource = Enumerable.Range(0, 100).Shuffle().ToArray().AsSpan();\nvar pool = ArrayPool\u003cint\u003e.Shared.Rent(randomSource.Length);\nvar indices = pool.AsSpan(0, randomSource.Length);\n\nQuickSelect.Iota(indices);\n\n//Get 50 \u003c= item \u003c 60\nQuickSelect.Execute(randomSource, indices, 50);\nQuickSelect.Execute(randomSource, indices[50..], 10);\n\nfor (int i = 0; i \u003c 10; i++)\n{\n    Console.Write($\"{randomSource[indices[50 + i]]}, \");\n}\n// output : 50, 56, 51, 57, 55, 54, 53, 52, 58, 59, \n\nArrayPool\u003cint\u003e.Shared.Return(pool);\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnenonaninu%2Fnthitemutils","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnenonaninu%2Fnthitemutils","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnenonaninu%2Fnthitemutils/lists"}