Unique characters in each string

Revision as of 16:00, 13 May 2021 by Nigel Galloway (talk | contribs) (Realize in F#)

Given a list of strings,   find characters appearing in each string and once only.

Unique characters in each string is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.
Task

The result should be given in alphabetical order: 1 2 3 a b c


Use the following list for this task:

        ["1a3c52debeffd", "2b6178c97a938stf", "3ycxdb1fgxa2yz"]


Other tasks related to string operations:
Metrics
Counting
Remove/replace
Anagrams/Derangements/shuffling
Find/Search/Determine
Formatting
Song lyrics/poems/Mad Libs/phrases
Tokenize
Sequences



AppleScript

<lang applescript>use AppleScript version "2.4" -- OS X 10.10 (Yosemite) or later use framework "Foundation"

on uniqueCharactersInEachString(listOfstrings)

   set astid to AppleScript's text item delimiters
   set AppleScript's text item delimiters to ""
   set countedSet to current application's class "NSCountedSet"'s setWithArray:(characters of (listOfstrings as text))
   set AppleScript's text item delimiters to astid
   set mutableSet to current application's class "NSMutableSet"'s setWithSet:(countedSet)
   repeat with thisString in listOfstrings
       tell mutableSet to intersectSet:(current application's class "NSSet"'s setWithArray:(thisString's characters))
       tell countedSet to minusSet:(mutableSet)
   end repeat
   tell mutableSet to minusSet:(countedSet)
   set sortDescriptor to current application's class "NSSortDescriptor"'s sortDescriptorWithKey:("self") ¬
       ascending:(true)
   
   return (mutableSet's sortedArrayUsingDescriptors:({sortDescriptor})) as list

end uniqueCharactersInEachString

uniqueCharactersInEachString({"1a3c52debeffd", "2b6178c97a938stf", "3ycxdb1fgxa2yz"})</lang>

Output:

<lang applescript>{"1", "2", "3", "a", "b", "c"}</lang>

F#

<lang fsharp> // Unique characters in each string: Nigel Galloway. May 12th., 2021 let fN g=g|>Seq.countBy id|>Seq.filter(fun(_,n)->n=1) let fUc g=g|>List.map fN|>Seq.concat|>Seq.countBy id|>Seq.filter(fun(_,n)->n=List.length g)|>Seq.map(fun((n,_),_)->n)|>Seq.sort printfn "%s" (fUc ["1a3c52debeffd";"2b6178c97a938stf";"3ycxdb1fgxa2yz"]|>Array.ofSeq|>System.String) </lang>

Output:
123abc

Factor

Works with: Factor version 0.99 2021-02-05

<lang factor>USING: io kernel sequences.interleaved sets sorting ;

{ "1a3c52debeffd" "2b6178c97a938sf" "3ycxdb1fgxa2yz" } [ intersect-all ] [ [ duplicates ] gather without ] bi natural-sort CHAR: space <interleaved> print

! How it works: ! intersect-all obtain elements present in every string -> "1a3c2bf" ! [ duplicates ] gather obtain elements that repeat within a single string -> "efd798xy" ! without from the first string, remove elements that are in the second -> "1a3c2b"</lang>

Output:
1 2 3 a b c

Julia

<lang julia>list = ["1a3c52debeffd", "2b6178c97a938stf", "3ycxdb1fgxa2yz"]

onceineachstring(list) = filter(c -> all(w -> count(x -> x == c, w) == 1, list), (sort ∘ unique ∘ prod)(list))

println(onceineachstring(list))

</lang>

Output:

['1', '2', '3', 'a', 'b', 'c']

Perl

<lang perl>#!/usr/bin/perl

use strict; # https://rosettacode.org/wiki/Unique_characters_in_each_string use warnings;

my @strings = ("1a3c52debeffd", "2b6178c97a938stf", "3ycxdb1fgxa2yz"); my $chars = join "\n", @strings; print "@{[ sort grep

 $chars !~ /$_.*$_/ &&           # the 'only once in each string' test
 @strings == $chars =~ s/$_//g,  # the 'in every string' test
 $chars =~ /./g ]}\n";</lang>
Output:
1 2 3 a b c

Phix

include builtins\sets.e

function once(integer ch, i, string s)
    integer l = length(s)
    return (i=1 or ch!=s[i-1])
       and (i=l or ch!=s[i+1])
end function

sequence set = {"1a3c52debeffd", "2b6178c97a938stf", "3ycxdb1fgxa2yz"},
         res = intersection(apply(true,filter,{apply(set,sort),once}))
printf(1,"found %d unique common characters: %s\n",{length(res),res})
Output:
found 6 unique common characters: 123abc

Raku

<lang perl6>my $strings = <1a3c52debeffd 2b6178c97a938stf 3ycxdb1fgxa2yz>;

put sort keys [∩] $strings.map: *.comb.Bag.grep: *.value == 1</lang>

Output:
1 2 3 a b c

REXX

This REXX program doesn't assume ASCII (or any other) order.   This example was run on an ASCII machine.

If this REXX program is run on an  ASCII  machine,   it will use the   ASCII   order of characters,   in this case,
decimal digits,   uppercase Latin letters,   and then lowercase Latin letters,   with other characters interspersed.

On an  EBCDIC  machine,   the order would be lowercase Latin letters,   uppercase Latin letters,   and then the
decimal digits,   with other characters interspersed.

On an  EBCDIC  machine,   the lowercase letters and the uppercase letters   aren't   contiguous. <lang rexx>/*REXX pgm finds and shows characters that are unique in each string and once only. */ parse arg $ /*obtain optional arguments from the CL*/ if $= | $="," then $= '1a3c52debeffd' "2b6178c97a938stf" '3ycxdb1fgxa2yz' if $= then do; say "***error*** no lists were specified."; exit 13; end

  1. = words($); $$= /*#: # words in $; $$: $ with no blanks*/
             do i=1  for #;    !.i= word($, i)  /*for speed, build a list of words in $*/
             $$= $$  ||  !.i                    /*build a list of all the strings.     */
             end   /*i*/

@= /*will be a list of all unique chars. */

  do j=0  for 256;        x= d2c(j)             /*process all the possible characters. */
  if pos(x, $$)==0               then iterate   /*Char not found in any string in  $ ? */
          do k=1  for #;  _= pos(x, !.k)        /*examine each string in the  $  list. */
          if _==0                then iterate j /*Character not found?   Then skip it. */
          if pos(x, !.k, _+1)>0  then iterate j /*    "     is a dup?      "    "   "  */
          end   /*k*/
  @= @ x                                        /*append a character, append it to list*/
  end   /*j*/                                   /*stick a fork in it,  we're all done. */

@@= space(@, 0); L= length(@@) /*elided superfluous blanks; get length*/ if @@== then @= " (none)" /*if none were found, pretty up message*/ if L==0 then L= "no" /*do the same thing for the # of chars.*/ say 'unique characters are: ' @ /*display the unique characters found. */ say say 'Found ' L " unique characters." /*display the # of unique chars found. */</lang>

output   when using the default input:
unique characters are:   1 2 3 a b c

Found  6  unique characters.

Ring

<lang ring> see "working..." + nl see "Unique characters in each string are:" + nl row = 0 str = "" cList = [] uniqueChars = ["1a3c52debeffd", "2b6178c97a938stf", "3ycxdb1fgxa2yz"] lenChars = len(uniqueChars)

for n = 1 to lenChars

   str = str + uniqueChars[n]

next

for n = 1 to len(str)

   flag = 1
   for m = 1 to lenChars
       cnt = count(uniqueChars[m],str[n])
       if cnt != 1
          flag = 0
          exit
       ok
   next
   if flag = 1
      ind = find(cList,str[n])
      if ind = 0
         add(cList,str[n])
      ok
   ok

next cList = sort(cList) for n = 1 to len(cList)

   row = row + 1
   see "" + cList[n] + " "

next see nl

see "Found " + row + " unique characters in each string" + nl see "done..." + nl

func count(cString,dString)

    sum = 0
    while substr(cString,dString) > 0
          sum++
          cString = substr(cString,substr(cString,dString)+len(string(sum)))
    end
    return sum

</lang>

Output:
working...
Unique characters in each string are:
1 2 3 a b c 
Found 6 unique characters in each string
done...

Wren

Library: Wren-seq
Library: Wren-sort

<lang ecmascript>import "/seq" for Lst import "/sort" for Sort

var strings = ["1a3c52debeffd", "2b6178c97a938stf", "3ycxdb1fgxa2yz"] var uniqueChars = [] for (s in strings) {

   var u = Lst.individuals(s.toList).where { |l| l[1] == 1 }.map { |l| l[0] }
   uniqueChars.addAll(u)

} var n = strings.count uniqueChars = Lst.individuals(uniqueChars).where { |l| l[1] == n }.map { |l| l[0] }.toList Sort.insertion(uniqueChars) System.print("Found %(uniqueChars.count) unique character(s) common to each string, namely:") System.print(uniqueChars.join(" "))</lang>

Output:
Found 6 unique character(s) common to each string, namely:
1 2 3 a b c