As the correct Answer by Andy Turner said, use a Set for tracking individual objects rather than a Map for pairs of objects.
Code point
The char type (and its wrapper class Character) is legacy, and is essentially broken. As a 16-bit value, it is not capable of representing most characters.
Instead, use code point integer numbers.
public static String firstRecurringCharacter ( List < String > inputs )
{
Objects.requireNonNull( inputs );
Set < Integer > seen = new HashSet <>();
for ( String s : inputs )
{
Objects.requireNonNull( s , "Input of list of String objects contained a null." );
if ( s.length() != 1) throw new IllegalStateException( "Input of list of String objects contained an element with other than one character." );
if ( ! seen.add( s.codePointAt( 0 ) ) )
{
return s;
}
}
return null;
}
Usage.
List < String > inputX = List.of( "D" , "B" , "C" , "A" , "B" , "A" );
List < String > inputY = List.of( "D" , "B" , "C" , "A" , "E" , "T" );
System.out.println( App5.firstRecurringCharacter( inputX ) );
System.out.println( App5.firstRecurringCharacter( inputY ) );
When run.
B
null
Optional
Returning null as a legitimate value is problematic. In such a case, use an Optional wrapper.
public static Optional < String > firstRecurringCharacter ( List < String > inputs )
{
Objects.requireNonNull( inputs );
Set < Integer > seen = new HashSet <>();
for ( String s : inputs )
{
Objects.requireNonNull( s , "Input of list of String objects contained a null." );
if ( s.length() != 1 ) throw new IllegalStateException( "Input of list of String objects contained an element with other than one character." );
if ( ! seen.add( s.codePointAt( 0 ) ) )
{
return Optional.of( s );
}
}
return Optional.empty();
}
Usage.
List < String > inputX = List.of( "D" , "B" , "C" , "A" , "B" , "A" );
List < String > inputY = List.of( "D" , "B" , "C" , "A" , "E" , "T" );
System.out.println( App5.firstRecurringCharacter( inputX ).orElse( "No recurring characters." ) );
System.out.println( App5.firstRecurringCharacter( inputY ).orElse( "No recurring characters." ) );
When run.
B
No recurring characters.
String rather than list of characters
Of course in the code above you need not use code point integers given an input of strings with a single character each. You could just make a Set< String > rather than Set< Integer > for code points.
Where the code points are useful is in tearing apart a string of multiple characters. So the calling programmer need not pass a collection of single-character strings. Instead, a String of several characters could be passed.
public static Optional < String > firstRecurringCharacter ( String input )
{
Objects.requireNonNull( input );
int[] codePoints = input.codePoints().toArray();
Set < Integer > seen = new HashSet <>();
for ( int codePoint : codePoints )
{
if ( ! seen.add( codePoint ) )
{
return Optional.of( Character.toString( codePoint ) );
}
}
return Optional.empty();
}
Usage.
String inputX = "DBCABA";
String inputY = "DBCAET";
String inputZ = "😷ABC😷ABC";
System.out.println( App5.firstRecurringCharacter( inputX ).orElse( "No recurring characters." ) );
System.out.println( App5.firstRecurringCharacter( inputY ).orElse( "No recurring characters." ) );
System.out.println( App5.firstRecurringCharacter( inputZ ).orElse( "No recurring characters." ) );
When run.
B
No recurring characters.
😷
Mapif you're going to return immediately upon finding the duplicate? Just use aSet.