{"id":20031482,"url":"https://github.com/rotorgames/rg.diffutils","last_synced_at":"2025-05-05T04:31:29.458Z","repository":{"id":66334539,"uuid":"376791442","full_name":"rotorgames/Rg.DiffUtils","owner":"rotorgames","description":"Rg.DiffUtils is a powerful tool that allows to merge collections and find differences","archived":false,"fork":false,"pushed_at":"2021-06-19T19:01:27.000Z","size":88,"stargazers_count":13,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-05-01T02:48:59.863Z","etag":null,"topics":[],"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/rotorgames.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":"2021-06-14T10:56:01.000Z","updated_at":"2024-11-08T20:36:14.000Z","dependencies_parsed_at":"2023-04-16T00:18:06.527Z","dependency_job_id":null,"html_url":"https://github.com/rotorgames/Rg.DiffUtils","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rotorgames%2FRg.DiffUtils","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rotorgames%2FRg.DiffUtils/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rotorgames%2FRg.DiffUtils/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rotorgames%2FRg.DiffUtils/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rotorgames","download_url":"https://codeload.github.com/rotorgames/Rg.DiffUtils/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252439705,"owners_count":21748057,"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-11-13T09:33:18.117Z","updated_at":"2025-05-05T04:31:29.448Z","avatar_url":"https://github.com/rotorgames.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"![Header](img/header.png)\n# Rg.DiffUtils [![Nuget](https://img.shields.io/nuget/v/Rg.DiffUtils)](https://www.nuget.org/packages/Rg.DiffUtils)\n\nRg.DiffUtils is a powerful tool that allows to merge collections and find differences.\n\nThe library uses Eugene W. Myers's algorithm to find differences and runs the second pass to find movements.\n\nThe difference between this library and the rest that this library expands the `ObservableCollection` and allows to notify UI or other elements about all changes in collections. \n\n## Compatibility\nThe library can be used in all platforms which support .NET Standard 1.0 or newer.\n\nSee more: https://docs.microsoft.com/en-us/dotnet/standard/net-standard#net-implementation-support\n\n## How To Use\n\n### DiffObservableCollection\n\nIn most cases, you can use the `DiffObservableCollection` for merging collections.\n\nThe class provides the `ReplaceDiff` method to merge a new collection into existing.\n\n```csharp\nvar array1 = new int[] { 1, 2, 3, 4, 5 };\nvar array2 = new int[] { 4, 5, 1, 6, 7 };\n\nvar collection = new DiffObservableCollection\u003cint\u003e(array1);\n\ncollection.ReplaceDiff(array2);\n```\n\nTo transform `array1` to `array2` the library runs 3 steps:\n- Add `6` and `7` to 5 and 6 positions\n- Remove `2` and `3` from 1 and 2 positions\n- Move `1` from 0 to 2 position\n\nAs you can see the library tries to optimize manipulations and batch several operations to one step. You can change this behavior in [DiffOptions](#diffoptions)\n\n### DiffUtil\nHowever, there are times when you can't use the `DiffObservableCollection`. For example, when you use your own implementation of the `IEnumerable`. \n\nIn this case, you can use the `DiffUtil` to calculate all steps for merging collections.\n\n```csharp\nvar array1 = new YourOwnCollection();\nvar array2 = new int[] { 4, 5, 1, 6, 7 };\n\nvar result = DiffUtil.CalculateDiff(array1, array2);\n```\n\n`DiffUtil.CalculateDiff` returns [DiffResult](#diffresult). You can use the `Steps` property to mutate your own collection step by step.\n\n### DiffOptions\n`DiffUtil.CalculateDiff`, `DiffObservableCollection.ReplaceDiff` and the `DiffObservableCollection` constructor can take an optional class the `DiffOptions`\n\n```csharp\nvar options = new DiffOptions\n{\n    AllowBatching = true, //Default: true. If it's false, all steps contain only one item even if items follow each other\n    DetectMoves = true //Default: true. If it's false, the second pass for movements detection doesn't work\n};\n```\n\n### IDiffEqualityComparer\nBy default `DiffUtil.CalculateDiff` uses `EqualityComparer\u003cT\u003e.Default` for comparing items but you can implement your own comparator.\n\nFor this case create `DiffEqualityComparer` which takes `IEqualityComparer` or a delegate in the constructor.\n\n```csharp\nvar diffComparer = new DiffEqualityComparer\u003cint\u003e(new YourEqualityComparer());\n// or\nvar diffComparer = new DiffEqualityComparer\u003cint\u003e((int oldItem, int newItem) =\u003e oldItem == newItem);\n```\nor implement `IDiffEqualityComparer`\n\n```csharp\nclass MyDiffEqualityComparer : IDiffEqualityComparer\u003cint\u003e\n{\n    public bool CompareItems(int oldItem, int newItem)\n    {\n        return oldItem == newItem;\n    }\n}\n```\n\n`IDiffEqualityComparer` can be used in `DiffUtil.CalculateDiff` but in `DiffObservableCollection` you have to use [IDiffHandler](#idiffhandler)\n\nAlso, you can use `ToDiffEqualityComparer` extension method to convert `IEqualityComparer` to `DiffEqualityComparer`\n\n### IDiffHandler\n`IDiffHandler` inherits from `IDiffEqualityComparer` and contains a new method `UpdateItem`.\n\nThe difference between `IDiffHandler` and `IDiffEqualityComparer` that the `IDiffHandler` updates equaled elements that allows applying new data to an existing item.\n\n```csharp\nclass MyDiffHandler : IDiffHandler\u003cMyCustomClass\u003e\n{\n    public bool CompareItems(MyCustomClass oldItem, MyCustomClass newItem)\n    {\n        return oldItem.Id == newItem.Id;\n    }\n\n    public void UpdateItem(MyCustomClass oldItem, MyCustomClass newItem)\n    {\n        // this method is invoked for each item if CompareItems was true\n\n        if (oldItem.Name != newItem.Name)\n            oldItem.Name = newItem.Name;\n    }\n}\n````\n\nIf you don't want to implement `IDiffHandler` you can use `DiffHandler` which takes `IDiffEqualityComparer`, `IEqualityComparer`, or a delegate as the first parameter, and an optional delegate which updates items as the second parameter\n\n```csharp\nvar array = new int[] { 4, 5, 1, 6, 7 };\nvar collection = new DiffObservableCollection\u003cint\u003e();\n\ncollection.ReplaceDiff(array, new DiffHandler\u003cint\u003e(new YourDiffEqualityComparer(), UpdateItems /*optional*/);\n//or\ncollection.ReplaceDiff(array, new DiffHandler\u003cint\u003e(new YourEqualityComparer(), UpdateItems /*optional*/);\n//or\ncollection.ReplaceDiff(array, new DiffHandler\u003cint\u003e((int x, int y) =\u003e x == y, UpdateItems /*optional*/);\n\nvoid UpdateItems(int oldItem, int newItem)\n{\n    // update oldItem here\n}\n```\n\nYou can use the `ToDiffHandler` extension method to convert `IEqualityComparer` or `IDiffEqualityComparer` to `DiffHandler`\n\n### DiffResult\n`DiffResult` contains all information about merging the first collection to the second.\n\n- `T[] OldSequence` The old collection converted to Array\n- `T[] NewSequence` The new collection converted to Array\n- `IReadOnlyList\u003cDiffItem\u003cT\u003e\u003e SameItems` MovedItems and NotMovedItems items\n- `IReadOnlyList\u003cDiffItem\u003cT\u003e\u003e MovedItems` All moved same items\n- `IReadOnlyList\u003cDiffItem\u003cT\u003e\u003e NotMovedItems` All not moved same items\n- `IReadOnlyList\u003cDiffItem\u003cT\u003e\u003e RemovedItems` All items which were removed\n- `IReadOnlyList\u003cDiffItem\u003cT\u003e\u003e AddedItems` All items which were added\n- `IReadOnlyList\u003cDiffStep\u003cT\u003e\u003e Steps` All the necessary steps to merge the new collection to the old\n\n## Thanks\nhttps://github.com/androidx/androidx\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frotorgames%2Frg.diffutils","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frotorgames%2Frg.diffutils","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frotorgames%2Frg.diffutils/lists"}