{"id":13431648,"url":"https://github.com/ninjanye/SearchExtensions","last_synced_at":"2025-03-16T12:30:52.262Z","repository":{"id":7784397,"uuid":"9154287","full_name":"ninjanye/SearchExtensions","owner":"ninjanye","description":"Library of IQueryable extension methods to perform searching","archived":false,"fork":false,"pushed_at":"2024-07-05T12:22:33.000Z","size":629,"stargazers_count":335,"open_issues_count":22,"forks_count":52,"subscribers_count":20,"default_branch":"master","last_synced_at":"2025-03-10T18:19:41.486Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/ninjanye.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.txt","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},"funding":{"github":["ninjanye"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"lfx_crowdfunding":null,"polar":null,"buy_me_a_coffee":null,"custom":null}},"created_at":"2013-04-01T19:29:34.000Z","updated_at":"2025-03-02T21:47:35.000Z","dependencies_parsed_at":"2024-12-05T19:00:36.448Z","dependency_job_id":"a87ab172-3211-4f23-87cf-ec0b60acb189","html_url":"https://github.com/ninjanye/SearchExtensions","commit_stats":{"total_commits":202,"total_committers":8,"mean_commits":25.25,"dds":"0.11386138613861385","last_synced_commit":"794da67b6cd2f591911d2ef55cb44df135134b7b"},"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ninjanye%2FSearchExtensions","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ninjanye%2FSearchExtensions/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ninjanye%2FSearchExtensions/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ninjanye%2FSearchExtensions/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ninjanye","download_url":"https://codeload.github.com/ninjanye/SearchExtensions/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243869178,"owners_count":20360967,"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":[],"created_at":"2024-07-31T02:01:04.780Z","updated_at":"2025-03-16T12:30:52.255Z","avatar_url":"https://github.com/ninjanye.png","language":"C#","funding_links":["https://github.com/sponsors/ninjanye"],"categories":["Frameworks, Libraries and Tools","Searching","框架, 库和工具","C# #"],"sub_categories":["Searching","搜索"],"readme":"# SearchExtensions\n\n[![NuGet](https://img.shields.io/nuget/v/ninjanye.searchextensions.svg)](https://www.nuget.org/packages/ninjanye.searchextensions/)\n[![Downloads](https://img.shields.io/nuget/dt/ninjanye.searchextensions.svg)](https://www.nuget.org/packages/ninjanye.searchextensions/)\n[![Stars](https://img.shields.io/github/stars/ninjanye/searchextensions?color=yellow)](https://github.com/ninjanye/searchextensions/stargazers)\n[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE.md)\n\nSearchExtensions is a library of IQueryable and IEnumerable extension methods to perform searching. More information on these packages and it's use can be found by, visiting [my blog](http://jnye.co/posts/tagged/search).\n\nThis project represents the source code for the following 3 nuget packages:\n\n* [NinjaNye.SearchExtensions](https://www.nuget.org/packages/NinjaNye.SearchExtensions/) - _A fluent api for performing complex searches across `IEnumerable` and `IQueryable` collections._\n* [NinjaNye.SearchExtensions.Levenshtein](https://www.nuget.org/packages/NinjaNye.SearchExtensions.Levenshtein/) - _This package specialises in performing Levenshtein searches across `IEnumerable` collections._\n* [NinjaNye.SearchExtensions.Soundex](https://www.nuget.org/packages/NinjaNye.SearchExtensions.Soundex/) - _This package specialises in performing [Soundex](http://en.wikipedia.org/wiki/Soundex) searches across `IEnumerable` collections._\n\n## Release notes\n\n* Soundex support migrated to dedicated [nuget package](https://www.nuget.org/packages/NinjaNye.SearchExtensions.Soundex/)\n* Levenshtein support migrated to dedicated [nuget package](https://www.nuget.org/packages/NinjaNye.SearchExtensions.Levenshtein/)\n* Constructed expressions can now be pulled out and re-used.\n\n\u003e As of version 3.0 Soundex and Levenshtein support has been migrated into their own respective packages (above).  All functionality still remains. If you are currently using Levensthein or Soundex functionlity in version 2.2 or lower, please upgrade to you the dedicated package.\n\n## IQueryable Searching\n\nThe IQueryable extension methods build expression trees based on your command chain and then sends this request to the data provider when required.  This means that your data provider is restricting the records that are brought into memory instead of having all records brought into, and filtered, in memory.\n\n### Methods\n\nSearch methods available to IQueryable data are:\n\n* `Containing` - target property *contains* search term or terms\n* `IsEqual` - target property *equals* search term or terms\n* `StartsWith` - target property *starts with* search term or terms\n\n### How to: Performing `Containing` searches\n\nSearch for a **single search term** within a **single property**\n\n    var result = queryableData.Search(x =\u003e x.Property1)\n                              .Containing(\"searchTerm\");\n\nSearch for a **single search term** within **multiple properties**\n\n    var result = queryableData.Search(x =\u003e x.Property1,\n                                      x =\u003e x.Property2,\n                                      x =\u003e x.Property3)\n                              .Containing(\"searchTerm\");\n\nSearch for **multiple search terms** within a **single property**\n\n    var result = queryableData.Search(x =\u003e x.Property1)\n                              .Containing(\"search\", \"term\");\n\nSearch for **multiple search terms** within **multiple properties**\n\n    var result = queryableData.Search(x =\u003e x.Property1,\n                                      x =\u003e x.Property2,\n                                      x =\u003e x.Property3)\n                              .Containing(\"searchTerm1\",\n                                          \"searchTerm2\",\n                                          \"searchTerm3\");\n\n### How to: Performing `Containing` AND searches\n\nSearch where a **single property** contains a **single search term**  \nAND a **another property** contains a **single search term**\n\n    var result = queryableData.Search(x =\u003e x.Property1)\n                              .Containing(\"searchTerm1\")\n                              .Search(x =\u003e x.Property1)\n                              .Containing(\"searchTerm2\");\n\nSearch where a **single search term** exists within in Property1 OR Property2  \nAND **single search term** exists within in Property3 OR Property4\n\n    var result = queryableData.Search(x =\u003e x.Property1, x =\u003e x.Property2)\n                              .Containing(\"searchTerm\")\n                              .Search(x =\u003e x.Property3, x =\u003e x.Property4)\n                              .Containing(\"searchTerm\");\n\nSearch where a **single search term** exists in Property1 OR Property2  \nAND any of the **multiple search terms** exist within a **single property**\n\n    var result = queryableData.Search(x =\u003e x.Property1, x =\u003e x.Property2)\n                              .Containing(\"searchTerm\")\n                              .Search(x =\u003e x.Property3)\n                              .Containing(\"another\", \"term\");\n\n### How to: Performing `IsEqual` searches\n\nSearch where a **single property** equals a **single search term**\n\n    var result = queryableData.Search(x =\u003e x.Property1)\n                              .IsEqual(\"searchTerm\");\n\nSearch where any one of **multiple properties** is equal to a **single search term**\n\n    var result = queryableData.Search(x =\u003e x.Property1,\n                                      x =\u003e x.Property2,\n                                      x =\u003e x.Property3)\n                              .IsEqual(\"searchTerm\");\n\nSearch where a **single property** is equal to any one of **multiple search terms**\n\n    var result = queryableData.Search(x =\u003e x.Property1)\n                              .IsEqual(\"search\", \"term\");\n\nSearch where any one of **multiple properties** is equal to any one of **multiple search terms**\n\n    var result = queryableData.Search(x =\u003e x.Property1,\n                                      x =\u003e x.Property2,\n                                      x =\u003e x.Property3)\n                              .IsEqual(\"searchTerm1\",\n                                       \"searchTerm2\",\n                                       \"searchTerm3\");\n\n### How to: Performing `StartsWith` searches\n\nSearch where a **single property** starts with a **single search term**\n\n    var result = queryableData.Search(x =\u003e x.Property1)\n                              .StartsWith(\"searchTerm\");\n\nSearch where any one of **multiple properties** starts with to a **single search term**\n\n    var result = queryableData.Search(x =\u003e x.Property1,\n                                      x =\u003e x.Property2,\n                                      x =\u003e x.Property3)\n                              .StartsWith(\"searchTerm\");\n\nSearch where a **single property** starts with any one of **multiple search terms**\n\n    var result = queryableData.Search(x =\u003e x.Property1)\n                              .StartsWith(\"search\", \"term\");\n\nSearch where any one of **multiple properties** starts with any one of **multiple search terms**\n\n    var result = queryableData.Search(x =\u003e x.Property1,\n                                      x =\u003e x.Property2,\n                                      x =\u003e x.Property3)\n                              .StartsWith(\"searchTerm1\",\n                                          \"searchTerm2\",\n                                          \"searchTerm3\");\n\n### How to: Combining instructions\n\nWith the latest version of SearchExtensions you can also combine search actions. For instance\n\nSearch where a **single property** `starts with` a **single search term** AND `containing` a **single search term**\n\n    var result = queryableData.Search(x =\u003e x.Property1)\n                              .StartsWith(\"abc\")\n                              .Containing(\"mno\");\n\nThe ability to pass **multiple search terms** to any of the action methods still remains:\n\n    var result = queryableData.Search(x =\u003e x.Property1, x =\u003e x.Property2)\n                              // that starts with \"abc\" OR \"ninja\"\n                              .StartsWith(\"abc\", \"ninja\")\n                              // and contains \"xyz\" OR \"extensions\"\n                              .Containing(\"xyz\", \"extensions\")  \n\n## IEnumerable (in memory) Searches\n\nSearchExtensions has also been extended to support `IEnumerable` collections.\n\nThis means you can now perform all of the above searches on in memory collections should you need to.\n\n### Methods\n\nCurrently `IEnumerable` searching has more features available to it than `IQueryable`, namely `EndsWith` and `SetCulture`\n\n* `SetCulture` - Sets the string comparison culture with which to perform searches\n* `Containing` - target property *contains* search term or terms\n* `IsEqual` - target property *equals* search term or terms\n* `StartsWith` - target property *starts with* search term or terms\n* `EndsWith` - target property *ends with* search term or terms\n\nThe important thing to remember when performing an in memory search is to set the culture to the type of string comparison you wish to perform. **If `SetCulture` is not specified, `StringComparison.CurrentCulture` is used.**\n\n### How to: Performing IEnumerable searches\n\nThese methods are identical to that of the `IQueryable` methods.\n\n    var result = enumerableData.Search(x =\u003e x.Property1)\n                               .SetCulture(StringComparison.OrdinalIgnoreCase) // Set culture for comparison\n                               .StartsWith(\"abc\")\n                               .EndsWith(\"xyz\")\n                               .Containing(\"mno\");\n\nIt is also possible to switch the `StringComparison` culture context multiple times\n\n    var result = enumerableData.Search(x =\u003e x.Property1)\n                               .SetCulture(StringComparison.OrdinalIgnoreCase)\n                               .StartsWith(\"abc\")  // Uses OrdinalIgnoreCase\n                               .SetCulture(StringComparison.Ordinal)\n                               .EndsWith(\"xyz\")    // Uses Ordinal\n                               .SetCulture(StringComparison.CurrentCulture)\n                               .Containing(\"mno\"); //Uses CurrentCulture\n\n## [Ranked Searches](http://jnye.co/Posts/2031/searchextensions-ranked-searches-now-supported-by-the-fluent-api)\n\nAnother feature of the fluent api across both `IQueryable` and `IEnumerable` collections is the `ToRanked()` method.  \n\nAs well as returning the matched items, a Ranked Search also returns a hit count for each item in the form of an IRanked\\\u003cT\\\u003e result.  This enables you to order by hit count to retrieve the most relevant search results.\n\n### `IRanked\u003cT\u003e` result\n\nAn IRanked\\\u003cT\\\u003e result is simply defined as follows:\n\n    public interface IRanked\u003cout T\u003e\n    {\n        int Hits { get; }\n        T Item { get; }\n    }\n\nThis is returned using the `ToRanked()` method:\n\nRankedSearch for a **single search term** within a **single property**\n\n    var result = queryableData.Search(x =\u003e x.Property1)\n                              .Containing(\"searchTerm\")\n                              .ToRanked();\n\nRankedSearch for a **single search term** within **multiple properties**\n\n    var result = queryableData.Search(x =\u003e x.Property1, x =\u003e x.Property2, x =\u003e x.Property3)\n                              .Containing(\"searchTerm\")\n                              .ToRanked();\n\nRankedSearch for **multiple search terms** within a **single property**\n\n    var result = queryableData.Search(x =\u003e x.Property1)\n                              .Containing(\"searchTerm1\", \"searchTerm2\", \"searchTerm3\")\n                              .ToRanked();\n\nRankedSearch for **multiple search terms** within **multiple properties**\n\n    var result = queryableData.Search(x =\u003e x.Property1, x =\u003e x.Property2)\n                              .Containing(\"searchTerm1\", \"searchTerm2\", \"searchTerm3\")\n                              .ToRanked();\n\n### Retrieve most relevant search results\n\nUsing ranked search you can now easily order your search results by the most relevant.  This following example assumes we have a list of `User` which has `FirstName`, `LastName` and `MiddleName` string properties. In this example we want to match on those with \"John\" in their name and retrieve the top 10 results.\n\n    var result = context.Users.Search(x =\u003e x.FirstName, x =\u003e x.LastName, x.MiddleName)\n                              .Containing(\"John\")\n                              .ToRanked()\n                              .OrderByDescending(r =\u003e r.Hits) // Order by Hits property of IRanked\u003cUser\u003e\n                              .Take(10);\n\n### Mixing it up\n\nWe can also mix it up with the other fluent API methods\n\n    var result = context.Users.Search(x =\u003e x.FirstName, x =\u003e x.LastName, x =\u003e x.MiddleName)\n                              .StartsWith(\"john\")\n                              .Containing(\"nye\")\n                              .ToRanked()\n                              .OrderByDescending(r =\u003e r.Hits) // Order by Hits property of IRanked\u003cUser\u003e\n                              .Take(10);\n\n### A word of note\n\nBe aware that the `ToRanked()` method uses the search terms of the `Containing()` method combined with the properties to search to build its hit count.  The fluent `ToRanked()` method also means the old `RankedSearch` method is now depreciated.  It still lives in the code but will soon be removed so please update your code to use the fluent api.\n\n## Soundex support [![Downloads](https://img.shields.io/nuget/dt/ninjanye.searchextensions.soundex.svg)](https://www.nuget.org/packages/ninjanye.searchextensions.soundex/)\n\n[NinjaNye.SearchExtensions.Soundex](https://www.nuget.org/packages/NinjaNye.SearchExtensions.Soundex/) supports converting and searching for words that sound like a given word.  \n\n### How to: Performing `Soundex` searches  \n\nReturning records that 'sound like' \"test\" using the [Soundex algorythm](http://en.wikipedia.org/wiki/Soundex):\n\nSearch where a **single property** sounds like a **single search term**\n\n    var result = data.SoundexOf(x =\u003e x.Property1).Matching(\"test\")\n\nSearch where a any of **multiple properties** sounds like a **single search term**\n\n    var result = data.SoundexOf(x =\u003e x.Property1, x =\u003e x.PropertyTwo)\n                     .Matching(\"test\")\n\nSearch where a **single property** sounds like any one of **multiple search terms**\n\n    var result = data.SoundexOf(x =\u003e x.Property1).Matching(\"test\", \"another\")\n\nSearch where a any of **multiple properties** sounds like any of **multiple search terms**\n\n    var result = data.SoundexOf(x =\u003e x.Property1, x =\u003e x.PropertyTwo)\n                     .Matching(\"test\", \"another\")\n\n### How to: Performing `ReverseSoundex` searches  \n\nAll the abouve soundex axamples can be performed using the [Reverse Soundex algorythm](http://en.wikipedia.org/wiki/Soundex).\nSimply substitute in the `ReverseSoundexOf()` method. For example: \n\nSearch where a **single property** sounds like a **single search term**\n\n    var result = data.ReverseSoundexOf(x =\u003e x.Property1).Matching(\"test\")\n\nSearch where a any of **multiple properties** sounds like a **single search term**\n\n    var result = data.ReverseSoundexOf(x =\u003e x.Property1, x =\u003e x.PropertyTwo)\n                     .Matching(\"test\")\n\n\u003e The above `SoundexOf` and `ReverseSoundexOf` methods can also be applied to `IQueryable` data.  For `IQueryable` we reduce the amount of records returned from the data source as much as possible but be aware that the soundex searching is performed on the _in memory collection_.\n\nFor more information about the Soundex search functionality, soundex search performance, and how it has been integrated with `IQueryable`, please visit [http://jnye.co/soundex](http://jnye.co/soundex)\n\n---\n\n\u003e If you have any new feature requests, questions, or comments, please get in touch, either, via my [website](http://jnye.co), [twitter](https://twitter.com/ninjanye) or preferrably raise an issue in this github repository.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fninjanye%2FSearchExtensions","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fninjanye%2FSearchExtensions","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fninjanye%2FSearchExtensions/lists"}