How to resolve the algorithm Determine if a string has all unique characters step by step in the Haskell programming language

Published on 7 June 2024 03:52 AM

How to resolve the algorithm Determine if a string has all unique characters step by step in the Haskell programming language

Table of Contents

Problem Statement

Given a character string   (which may be empty, or have a length of zero characters):

Use (at least) these five test values   (strings):

Show all output here on this page.

Let's start with the solution:

Step by Step solution about How to resolve the algorithm Determine if a string has all unique characters step by step in the Haskell programming language

Haskell Code Overview

This Haskell code defines functions for finding and displaying information about duplicated characters in strings and creating a table to present the results.

Key Functions:

  • hexFromChar: Converts a character to its hexadecimal representation.
  • string: Encloses a string in double quotes.
  • char: Encloses a character in single quotes.
  • size: Returns the length of a string.
  • positions: Converts a tuple of integers representing positions into a string.
  • forTable: Generates a list of strings for a given string, including its length, uniqueness status, first difference (if any), hexadecimal representation of the first difference, and positions of the first difference.
  • showTable: Formats and displays a table with the specified header, vertical and horizontal borders, separator, and content.
  • table: Generates a table with the given content.
  • allUnique: Determines if all characters in a string are unique, returning the first difference and its positions if not unique.
  • duplicatedCharIndices: Finds the first duplicated character and its indices in a string if it exists.

Usage:

The main functions call the above functions to process a list of strings, find duplicated characters, and display the results in a formatted table.

Detailed Explanation:

  1. Hexadecimal Conversion: hexFromChar converts a character to its corresponding hexadecimal representation as a string.

  2. Enclosing Strings and Characters: string and char wrap strings and characters in quotes for display purposes.

  3. Length Calculation: size determines the length of a string and returns it as a string.

  4. Position Conversion: positions converts a tuple of integers representing positions into a string.

  5. Table Generation: forTable generates a list of strings for a specific string, including its length, uniqueness status, first difference, hexadecimal representation of the first difference, and positions of the first difference.

  6. Table Formatting: showTable formats and presents the table with the specified header, borders, and separator.

  7. All Unique: allUnique checks if all characters in a string are unique, producing a Maybe value with the first difference and its positions if non-unique.

  8. Duplicated Character Indices: duplicatedCharIndices identifies the first duplicated character and its indices in a string if it exists.

  9. Main Functions: The main functions use these functions to process a list of strings, finding duplicated characters, and displaying the results in a table.

Source code in the haskell programming language

import Data.List (groupBy, intersperse, sort, transpose)
import Data.Char (ord, toUpper)
import Data.Function(on) 
import Numeric (showHex)


hexFromChar :: Char -> String
hexFromChar c = map toUpper $ showHex (ord c) ""
 
string :: String -> String
string xs = ('\"' : xs) <> "\""
 
char :: Char -> String
char c = ['\'', c, '\'']
 
size :: String -> String
size = show . length
 
positions :: (Int, Int) -> String
positions (a, b) = show a <> " " <> show b
 
forTable :: String -> [String]
forTable xs = string xs : go (allUnique xs)
  where
    go Nothing = [size xs, "yes", "", "", ""]
    go (Just (u, ij)) = [size xs, "no", char u, hexFromChar u, positions ij]
 
showTable :: Bool -> Char -> Char -> Char -> [[String]] -> String
showTable _ _ _ _ [] = []
showTable header ver hor sep contents =
  unlines $
  hr :
  (if header
     then z : hr : zs
     else intersperse hr zss) <>
  [hr]
  where
    vss = map (map length) contents
    ms = map maximum (transpose vss) :: [Int]
    hr = concatMap (\n -> sep : replicate n hor) ms <> [sep]
    top = replicate (length hr) hor
    bss = map (map (`replicate` ' ') . zipWith (-) ms) vss
    zss@(z:zs) =
      zipWith
        (\us bs -> concat (zipWith (\x y -> (ver : x) <> y) us bs) <> [ver])
        contents
        bss
 
table xs =
  showTable
    True
    '|'
    '-'
    '+'
    (["string", "length", "all unique", "1st diff", "hex", "positions"] :
     map forTable xs)
 
allUnique
  :: (Ord b, Ord a, Num b, Enum b)
  => [a] -> Maybe (a, (b, b))
allUnique xs = go . groupBy (on (==) fst) . sort . zip xs $ [0 ..]
  where
    go [] = Nothing
    go ([_]:us) = go us
    go (((u, i):(_, j):_):_) = Just (u, (i, j))
 
main :: IO ()
main =
  putStrLn $
  table ["", ".", "abcABC", "XYZ ZYX", "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ"]


import Data.List (groupBy, intercalate, sortOn)
import Data.Function (on)
import Numeric (showHex)
import Data.Char (ord)


------------- INDICES OF DUPLICATED CHARACTERS -----------

duplicatedCharIndices :: String -> Maybe (Char, [Int])
duplicatedCharIndices s
  | null duplicates = Nothing
  | otherwise =
    Just $
    ((,) . (snd . head) <*> fmap fst) (head (sortOn (fst . head) duplicates))
  where
    duplicates =
      filter ((1 <) . length) $
      groupBy (on (==) snd) $ sortOn snd $ zip [0 ..] s


--------------------------- TEST -------------------------
main :: IO ()
main =
  putStrLn $
  fTable
    "First duplicated character, if any:"
    (fmap (<>) show <*> ((" (" <>) . (<> ")") . show . length))
    (maybe
       "None"
       (\(c, ixs) ->
           unwords
             [ show c
             , "(0x" <> showHex (ord c) ") at"
             , intercalate ", " (show <$> ixs)
             ]))
    duplicatedCharIndices
    ["", ".", "abcABC", "XYZ ZYX", "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ"]


------------------------- DISPLAY ------------------------

fTable :: String -> (a -> String) -> (b -> String) -> (a -> b) -> [a] -> String
fTable s xShow fxShow f xs =
  unlines $
  s : fmap (((<>) . rjust w ' ' . xShow) <*> ((" -> " <>) . fxShow . f)) xs
  where
    rjust n c = drop . length <*> (replicate n c <>)
    w = maximum (length . xShow <$> xs)


import qualified Safe as S
import qualified Data.Map.Strict as M
import Data.List (intercalate, foldl') --'
import Data.Ord (comparing)
import Numeric (showHex)
import Data.Char (ord)


----------- INDICES OF ANY DUPLICATED CHARACTERS ---------

duplicatedCharIndices :: String -> Maybe (Char, [Int])
duplicatedCharIndices xs =
  S.minimumByMay
    (comparing (head . snd))
    (M.toList
       (M.filter
          ((1 <) . length)
          (foldl' --'
             (\a (i, c) -> M.insert c (maybe [i] (<> [i]) (M.lookup c a)) a)
             M.empty
             (zip [0 ..] xs))))

-- OR, fusing filter, toList, and minimumByMay down to a single fold:
duplicatedCharIndices_ :: String -> Maybe (Char, [Int])
duplicatedCharIndices_ xs =
  M.foldrWithKey
    go
    Nothing
    (foldl' --'
       (\a (i, c) -> M.insert c (maybe [i] (<> [i]) (M.lookup c a)) a)
       M.empty
       (zip [0 ..] xs))
  where
    go k [_] mb = mb -- Unique
    go k xs Nothing = Just (k, xs) -- Duplicated
    go k xs@(x:_) (Just (c, ys@(y:_)))
      | x < y = Just (k, xs) -- Earlier duplication
      | otherwise = Just (c, ys)

--------------------------- TEST -------------------------
main :: IO ()
main =
  putStrLn $
  fTable
    "First duplicated character, if any:"
    ((<>) <$> show <*> ((" (" <>) . (<> ")") . show . length))
    (maybe
       "None"
       (\(c, ixs) ->
           unwords
             [ show c
             , "(0x" <> showHex (ord c) ") at"
             , intercalate ", " (show <$> ixs)
             ]))
    duplicatedCharIndices_
    ["", ".", "abcABC", "XYZ ZYX", "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ"]

------------------------- DISPLAY ------------------------
fTable :: String -> (a -> String) -> (b -> String) -> (a -> b) -> [a] -> String
fTable s xShow fxShow f xs =
  unlines $
  s : fmap (((<>) . rjust w ' ' . xShow) <*> ((" -> " <>) . fxShow . f)) xs
  where
    rjust n c = drop . length <*> (replicate n c <>)
    w = maximum (length . xShow <$> xs)


  

You may also check:How to resolve the algorithm Narcissist step by step in the PARI/GP programming language
You may also check:How to resolve the algorithm Fibonacci sequence step by step in the Klingphix programming language
You may also check:How to resolve the algorithm Delete a file step by step in the Smalltalk programming language
You may also check:How to resolve the algorithm Composite numbers k with no single digit factors whose factors are all substrings of k step by step in the EasyLang programming language
You may also check:How to resolve the algorithm Runtime evaluation step by step in the ALGOL 68 programming language