Skip to content

fix: keep elements that compare equal in insertion order in OrderedCollection [patch] - #91

Merged
matt-edmondson merged 1 commit into
mainfrom
claude/containers-80-stable-equal-order
Sep 29, 2026
Merged

matt-edmondson merged 1 commit into
mainfrom
claude/containers-80-stable-equal-order

Conversation

@matt-edmondson

Copy link
Copy Markdown
Contributor

Fixes #80

What was wrong

OrderedCollection<T>.Add inserted at whatever index BinarySearch returned. When other elements already compared equal, that index could be any of them, so where a new equal element landed depended on where the search happened to probe. Clone(), GetRange() and the IEnumerable constructors all rebuild by re-adding each item. Each rebuild shuffled equal elements again, so with a key-only comparer a copy was not sequence-equal to its source.

Change

  • Add now inserts at the upper bound, just after the last element that compares equal. A new private FindUpperBound does this, mirroring the existing FindFirst. Equal elements keep insertion order, so rebuilding a collection from its own sequence gives back the same sequence.
  • Clone and GetRange are unchanged. They now preserve order because Add is stable, and since each item goes in at the end, a rebuild from already-sorted input no longer shifts elements.

Tests

Four new tests use a (int Key, string Name) element with a key-only comparer:

  • Add_KeyComparer_KeepsEqualElementsInInsertionOrder
  • Clone_KeyComparer_IsSequenceEqualToSource
  • GetRange_KeyComparer_IsSequenceEqualToSourceRange
  • Constructor_FromEnumerableWithKeyComparer_PreservesInputOrderOfEqualElements

With the fix reverted, all four fail. With it in place, the whole suite passes (dotnet test: 422 passed, 0 failed), and Containers.csproj builds with 0 warnings.

🤖 Generated with Claude Code

https://claude.ai/code/session_01EdrcmpMTNHSnACRgnNGs8v


Generated by Claude Code

…llection [patch]

Add inserted at whatever index BinarySearch returned, so among elements that
compare equal the order depended on where the search happened to probe.
Clone, GetRange and the enumerable constructors rebuild by re-adding, so each
rebuild shuffled equal elements again and a copy was not sequence-equal to its
source.

Add now inserts at the upper bound, after the last element that compares
equal. Equal elements keep insertion order, and rebuilding a collection from
its own sequence reproduces it.

Fixes #80

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EdrcmpMTNHSnACRgnNGs8v
@sonarqubecloud

Copy link
Copy Markdown

@matt-edmondson
matt-edmondson merged commit c48a11a into main Sep 29, 2026
12 checks passed
@matt-edmondson
matt-edmondson deleted the claude/containers-80-stable-equal-order branch September 29, 2026 01:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OrderedCollection.Clone() and GetRange() reorder elements that compare equal, so a clone isn't sequence-equal to its source

2 participants