4

I have a problem that should be trivial but to which I can't find any elegant answer.

I have an instance of a IList<string> and I want to get a comma-separated string of all its distinct (case-insensitive) values.

I thought I'd just use the string.Join helper for that since it has a nice overload that accepts an IEnumerator<string> as parameter. Unfortunately, I see to have hit a snag: spring4d redefines IEnumerator<T> and, of course, use its own type everywhere.

The result is that the following code does not compile:

var
  distinct: system.IEnumerator<string>;
begin
  result := inherited GetToken;
  if assigned(result) then
  begin
    if not Modules.Contains(STR_DID_SESSION_MODULE) then
      Modules.Add(STR_DID_SESSION_MODULE); 
    distinct := TDistinctIterator<string>.Create(Modules, TIStringComparer.Ordinal);
    result.CustomClaims.Items[STR_CLAIM_CUSTOM_MODULES] := string.Join(',', distinct);
  end;
end;

The assignment to distinct fails with E2010 Incompatible types: 'System.IEnumerator<System.string>' and 'Spring.Collections.Extensions.TDistinctIterator<System.string>'

Alternatively, if I remove the namespace from distinct, it's the call to string.Join that fails.

Any idea how I should be doing that ? Short of manually walking through the iteration and performing the join manually?

Stefan Glienke
  • 20,860
  • 2
  • 48
  • 102
Stephane
  • 3,173
  • 3
  • 29
  • 42

1 Answers1

5

Write it yourself (FWIW I would prefer opposite parameter order but I kept it like that since the signature of TStringHelper.Join):

function StringJoin(const separator: string; const values: Spring.Collections.IEnumerable<string>): string; overload;
var
  e: Spring.Collections.IEnumerator<string>;
begin
  e := values.GetEnumerator;
  if not e.MoveNext then
    Exit('');
  Result := e.Current;
  while e.MoveNext do
    Result := Result + separator + e.Current;
end;

Also you can write the code way shorter (no need to manually create the iterator from Spring.Collections.Extensions):

StringJoin(',', TEnumerable.Distinct<string>(Modules, TStringComparer.OrdinalIgnoreCase))

Now if we had interface helpers we could easily write a helper for IEnumerable<string> and add ToDelimitedString or something like that.

Stefan Glienke
  • 20,860
  • 2
  • 48
  • 102
  • Thank you but I can't find StringJoin anywhere ? Is it on a separate branch ? – Stephane Nov 27 '17 at 14:51
  • 1
    It's here in this answer - that is why I wrote "write it yourself" - otherwise I would have written "use it from ..." (forgot to pass the first parameter/the comma on the call in the last line though) – Stefan Glienke Nov 27 '17 at 14:52