I'm working on modernizing Rosetta Code's infrastructure. Starting with communications. Please accept this time-limited open invite to RC's Slack.. --Michael Mol (talk) 20:59, 30 May 2020 (UTC)

# Longest common suffix

Longest common suffix 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.

Write a function to find the longest common suffix string amongst an array of strings.

## ALGOL 68

Works with: ALGOL 68G version Any - tested with release 2.8.3.win32

Based on the Algol 68 sample for the Longest Common Prefix task.

`# find the longest common suffix of two strings #PRIO COMMONSUFFIX = 1;OP   COMMONSUFFIX = ( STRING a, b )STRING:    BEGIN        INT a pos := UPB a; INT a min = LWB a;        INT b pos := UPB b; INT b min = LWB b;        WHILE            IF a pos < a min OR b pos < b min THEN FALSE            ELSE a[ a pos ] = b[ b pos ]            FI        DO            a pos -:= 1; b pos -:= 1        OD;        a[ a pos + 1 : UPB a ]    END # COMMONSUFFIX # ;# get the length of a string #OP  LEN = ( STRING a )INT: ( UPB a + 1 ) - LWB a;# find the longest common suffix of an array of STRINGs #OP  LONGESTSUFFIX = ( []STRING list )STRING:    IF  UPB list < LWB list    THEN        # no elements #        ""    ELIF UPB list = LWB list    THEN        # only one element #        list[ LWB list ]    ELSE        # more than one element #        STRING suffix := list[ LWB list ] COMMONSUFFIX list[ 1 + LWB list ];        FOR pos FROM 2 + LWB list TO UPB list WHILE suffix /= "" DO            STRING next suffix := list[ pos ] COMMONSUFFIX suffix;            IF LEN next suffix < LEN suffix            THEN                # this element has a smaller common suffix #                suffix := next suffix            FI        OD;        suffix    FI ;# test the LONGESTSUFFIX operator #PROC test suffix = ( []STRING list, STRING expected result )VOID:    BEGIN        STRING suffix = LONGESTSUFFIX list;        print( ( "longest common suffix of (" ) );        FOR pos FROM LWB list TO UPB list DO print( ( " """, list[ pos ], """" ) ) OD;        print( ( " ) is: """, suffix, """ "               , IF suffix = expected result THEN "as expected" ELSE "NOT AS EXPECTED" FI                , newline               )             )    END # test suffix # ;[ 1 : 0 ]STRING empty list; # for recent versions of Algol 68G, can't just put "()" for an empty list #BEGIN    test suffix( ( "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ), "day" );    test suffix( ( "throne", "throne" ), "throne" );    test suffix( ( "throne", "dungeon" ), "" );    test suffix( ( "throne", "", "throne" ), "" );    test suffix( ( "cheese" ), "cheese" );    test suffix( ( "" ), "" );    test suffix( empty list, "" );    test suffix( ( "prefix", "suffix" ), "fix" );    test suffix( ( "send", "lend" ), "end" )END`
Output:
```longest common suffix of ( "Sunday" "Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "Saturday" ) is: "day" as expected
longest common suffix of ( "throne" "throne" ) is: "throne" as expected
longest common suffix of ( "throne" "dungeon" ) is: "" as expected
longest common suffix of ( "throne" "" "throne" ) is: "" as expected
longest common suffix of ( "cheese" ) is: "cheese" as expected
longest common suffix of ( "" ) is: "" as expected
longest common suffix of ( ) is: "" as expected
longest common suffix of ( "prefix" "suffix" ) is: "fix" as expected
longest common suffix of ( "send" "lend" ) is: "end" as expected
```

## AppleScript

### Procedural

The simplest solution in AppleScript seems to be to reverse the strings, apply the AppleScriptObjC solution for the Longest common prefix task, and reverse the result.

`use AppleScript version "2.4" -- OS X 10.10 (Yosemite) or lateruse framework "Foundation" on longestCommonSuffix(textList)    -- Eliminate any non-texts from the input.    if (textList's class is record) then return ""    set textList to (textList as list)'s text    if (textList is {}) then return ""     set astid to AppleScript's text item delimiters    set AppleScript's text item delimiters to ""    repeat with i from 1 to (count textList)        set item i of textList to (reverse of characters of item i of textList) as text    end repeat    set lcs to (reverse of characters of longestCommonPrefix(textList)) as text    set AppleScript's text item delimiters to astid     return lcsend longestCommonSuffix on longestCommonPrefix(textList)    -- Eliminate any non-texts from the input.    if (textList's class is record) then return ""    set textList to (textList as list)'s text    if (textList is {}) then return ""     -- Convert the AppleScript list to an NSArray of NSStrings.    set stringArray to current application's class "NSArray"'s arrayWithArray:(textList)     -- Compare the strings case-insensitively using a built-in NSString method.    set lcp to stringArray's firstObject()    repeat with i from 2 to (count stringArray)        set lcp to (lcp's commonPrefixWithString:(item i of stringArray) options:(current application's NSCaseInsensitiveSearch))        if (lcp's |length|() is 0) then exit repeat    end repeat     -- Return the NSString result as AppleScript text.    return lcp as textend longestCommonPrefix -- Tests and results:longestCommonSuffix({"throne", "sousaphone"}) --> "one"longestCommonSuffix({"prefix", "suffix"}) --> "fix"longestCommonSuffix({"remark", "spark", "aardvark"}) --> "ark"longestCommonSuffix({"ectoplasm", "banana"}) --> ""`

### Functional

and for more productivity, and higher re-use of library functions, we can write a functional definition (rather than a procedure):

`------------------- LONGEST COMMON SUFFIX ------------------  -- longestCommonSuffix :: [String] -> Stringon longestCommonSuffix(xs)    if 1 < length of xs then        reverse of map(my fst, ¬            takeWhile(my allSame, ¬                transpose(map(my |reverse|, xs)))) as text    else        xs as text    end ifend longestCommonSuffix  ---------------------------- TESTS --------------------------on run    script test        on |λ|(s)            set xs to words of s            showList(xs) & " -> '" & longestCommonSuffix(xs) & "'"        end |λ|    end script     unlines(map(test, {¬        "throne sousaphone tone", ¬        "prefix suffix infix", ¬        "remark spark aardvark lark", ¬        "ectoplasm banana brick"}))end run  --------------------- GENERIC FUNCTIONS -------------------- -- all :: (a -> Bool) -> [a] -> Boolon all(p, xs)    -- True if p holds for every value in xs    tell mReturn(p)        set lng to length of xs        repeat with i from 1 to lng            if not |λ|(item i of xs, i, xs) then return false        end repeat        true    end tellend all  -- allSame :: [a] -> Boolon allSame(xs)    if 2 > length of xs then        true    else        script p            property h : item 1 of xs            on |λ|(x)                h = x            end |λ|        end script        all(p, rest of xs)    end ifend allSame  -- comparing :: (a -> b) -> (a -> a -> Ordering)on comparing(f)    script        on |λ|(a, b)            tell mReturn(f)                set fa to |λ|(a)                set fb to |λ|(b)                if fa < fb then                    -1                else if fa > fb then                    1                else                    0                end if            end tell        end |λ|    end scriptend comparing  -- concatMap :: (a -> [b]) -> [a] -> [b]on concatMap(f, xs)    set lng to length of xs    set acc to {}    tell mReturn(f)        repeat with i from 1 to lng            set acc to acc & (|λ|(item i of xs, i, xs))        end repeat    end tell    return accend concatMap  -- foldl :: (a -> b -> a) -> a -> [b] -> aon foldl(f, startValue, xs)    tell mReturn(f)        set v to startValue        set lng to length of xs        repeat with i from 1 to lng            set v to |λ|(v, item i of xs, i, xs)        end repeat        return v    end tellend foldl  -- fst :: (a, b) -> aon fst(tpl)    if class of tpl is record then        |1| of tpl    else        item 1 of tpl    end ifend fst  -- intercalate :: String -> [String] -> Stringon intercalate(delim, xs)    set {dlm, my text item delimiters} to ¬        {my text item delimiters, delim}    set str to xs as text    set my text item delimiters to dlm    strend intercalate  -- justifyLeft :: Int -> Char -> String -> Stringon justifyLeft(n, cFiller)    script        on |λ|(strText)            if n > length of strText then                text 1 thru n of (strText & replicate(n, cFiller))            else                strText            end if        end |λ|    end scriptend justifyLeft  -- length :: [a] -> Inton |length|(xs)    set c to class of xs    if list is c or string is c then        length of xs    else        (2 ^ 29 - 1) -- (maxInt - simple proxy for non-finite)    end ifend |length|  -- map :: (a -> b) -> [a] -> [b]on map(f, xs)    -- The list obtained by applying f    -- to each element of xs.    tell mReturn(f)        set lng to length of xs        set lst to {}        repeat with i from 1 to lng            set end of lst to |λ|(item i of xs, i, xs)        end repeat        return lst    end tellend map  -- maximumBy :: (a -> a -> Ordering) -> [a] -> aon maximumBy(f, xs)    set cmp to mReturn(f)    script max        on |λ|(a, b)            if a is missing value or cmp's |λ|(a, b) < 0 then                b            else                a            end if        end |λ|    end script     foldl(max, missing value, xs)end maximumBy  -- min :: Ord a => a -> a -> aon min(x, y)    if y < x then        y    else        x    end ifend min  -- mReturn :: First-class m => (a -> b) -> m (a -> b)on mReturn(f)    -- 2nd class handler function lifted into 1st class script wrapper.     if script is class of f then        f    else        script            property |λ| : f        end script    end ifend mReturn  -- Egyptian multiplication - progressively doubling a list, appending-- stages of doubling to an accumulator where needed for binary -- assembly of a target length-- replicate :: Int -> a -> [a]on replicate(n, a)    set out to {}    if 1 > n then return out    set dbl to {a}     repeat while (1 < n)        if 0 < (n mod 2) then set out to out & dbl        set n to (n div 2)        set dbl to (dbl & dbl)    end repeat    return out & dblend replicate  -- reverse :: [a] -> [a]on |reverse|(xs)    if class of xs is text then        (reverse of characters of xs) as text    else        reverse of xs    end ifend |reverse|  -- showList :: [a] -> Stringon showList(xs)    script show        on |λ|(x)            if text is class of x then                "'" & x & "'"            else                x as text            end if        end |λ|    end script    if {} ≠ xs then        "[" & intercalate(", ", map(show, xs)) & "]"    else        "[]"    end ifend showList  -- take :: Int -> [a] -> [a]-- take :: Int -> String -> Stringon take(n, xs)    set c to class of xs    if list is c then        if 0 < n then            items 1 thru min(n, length of xs) of xs        else            {}        end if    else if string is c then        if 0 < n then            text 1 thru min(n, length of xs) of xs        else            ""        end if    else if script is c then        set ys to {}        repeat with i from 1 to n            set v to |λ|() of xs            if missing value is v then                return ys            else                set end of ys to v            end if        end repeat        return ys    else        missing value    end ifend take  -- takeWhile :: (a -> Bool) -> [a] -> [a]-- takeWhile :: (Char -> Bool) -> String -> Stringon takeWhile(p, xs)    if script is class of xs then        takeWhileGen(p, xs)    else        tell mReturn(p)            repeat with i from 1 to length of xs                if not |λ|(item i of xs) then ¬                    return take(i - 1, xs)            end repeat        end tell        return xs    end ifend takeWhile  -- transpose :: [[a]] -> [[a]]on transpose(rows)    set w to length of maximumBy(comparing(|length|), rows)    set paddedRows to map(justifyLeft(w, "x"), rows)     script cols        on |λ|(_, iCol)            script cell                on |λ|(row)                    item iCol of row                end |λ|            end script            concatMap(cell, paddedRows)        end |λ|    end script     map(cols, item 1 of rows)end transpose  -- unlines :: [String] -> Stringon unlines(xs)    -- A single string formed by the intercalation    -- of a list of strings with the newline character.    set {dlm, my text item delimiters} to ¬        {my text item delimiters, linefeed}    set str to xs as text    set my text item delimiters to dlm    strend unlines`
Output:
```['throne', 'sousaphone', 'tone'] -> 'one'
['prefix', 'suffix', 'infix'] -> 'fix'
['remark', 'spark', 'aardvark', 'lark'] -> 'ark'
['ectoplasm', 'banana', 'brick'] -> ''```

## AutoHotkey

`Longest_common_suffix(data){	for num, v in StrSplit(data.1)		for i, word in data				if (SubStr(word, 1-num) <> SubStr(data.1, 1-num))				return num=1 ? "" : SubStr(word, 2-num)	return SubStr(word, 1-num)}`
Examples:
`MsgBox % "". "`n" Longest_common_suffix(["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]). "`n" Longest_common_suffix(["throne", "throne"]). "`n" Longest_common_suffix(["throne", "dungeon"]). "`n" Longest_common_suffix(["throne", "", "throne"]). "`n" Longest_common_suffix(["cheese"]). "`n" Longest_common_suffix([""]). "`n" Longest_common_suffix(["prefix", "suffix"]). "`n" Longest_common_suffix(["bar", "foobar"])return`
Output:
```day
throne

cheese

fix
bar```

## BaCon

`FUNCTION Common_Suffix\$(data\$)     LOCAL x, size    LOCAL delim\$     REPEAT        delim\$ = ""        INCR size         FOR x = 1 TO AMOUNT(data\$)            delim\$ = APPEND\$(delim\$, 0, RIGHT\$(TOKEN\$(data\$, x), size))        NEXT    UNTIL AMOUNT(UNIQ\$(delim\$)) <> 1     RETURN RIGHT\$(TOKEN\$(data\$, 1), size-1) ENDFUNCTION PRINT "The common suffix is: '", Common_Suffix\$("baabababc baabc bbbabc"), "'"PRINT "The common suffix is: '", Common_Suffix\$("Monday Tuesday Wednesday Thursday Friday Saturday Sunday"), "'"PRINT "The common suffix is: '", Common_Suffix\$("longest common suffix"), "'"PRINT "The common suffix is: '", Common_Suffix\$("prefix suffix"), "'"PRINT "The common suffix is: '", Common_Suffix\$(""), "'"`
Output:
```The common suffix is: 'abc'
The common suffix is: 'day'
The common suffix is: ''
The common suffix is: 'fix'
The common suffix is: ''```

## Delphi

Library: Types
Translation of: Ring
` program Longest_common_suffix; {\$APPTYPE CONSOLE} uses  System.SysUtils,  Types; type  TStringDynArrayHelper = record helper for TStringDynArray  private    class function Compare(const s: string; a: TStringDynArray; subSize: integer):      Boolean;  public    function Reverse(value: string): string;    function LongestSuffix: string;    function Join(const sep: char): string;  end; { TStringDynArrayHelper } class function TStringDynArrayHelper.Compare(const s: string; a: TStringDynArray;  subSize: integer): Boolean;var  i: Integer;begin  for i := 0 to High(a) do    if s <> a[i].Substring(0, subSize) then      exit(False);  Result := True;end; function TStringDynArrayHelper.Join(const sep: char): string;begin  Result := string.Join(sep, self);end; function TStringDynArrayHelper.LongestSuffix: string;var  ALength: Integer;  i, lenMin, longest: Integer;  ref: string;begin  ALength := Length(self);   // Empty list  if ALength = 0 then    exit('');   lenMin := MaxInt;  for i := 0 to ALength - 1 do  begin    // One string is empty    if self[i].IsEmpty then      exit('');     self[i] := Reverse(self[i]);     // Get the minimum length of string    if lenMin > self[i].Length then      lenMin := self[i].Length;  end;   longest := -1;  repeat    inc(longest);    ref := self.Substring(0, longest + 1);  until not compare(ref, Self, longest + 1) or (longest >= lenMin);   Result := self.Substring(0, longest);  Result := reverse(Result);end; function TStringDynArrayHelper.Reverse(value: string): string;var  ALength: Integer;  i: Integer;  c: Char;begin  ALength := value.Length;  Result := value;   if ALength < 2 then    exit;   for i := 1 to ALength div 2 do  begin    c := Result[i];    Result[i] := Result[ALength - i + 1];    Result[ALength - i + 1] := c;  end;end; var  List: TStringDynArray; begin  List := ['baabababc', 'baabc', 'bbbabc'];   Writeln('Input:');  Writeln(List.Join(#10), #10);  Writeln('Longest common suffix = ', List.LongestSuffix);   Readln;end.  `
Output:
```Input:
baabababc
baabc
bbbabc

Longest common suffix = abc
```

## Factor

Works with: Factor version 0.99 2020-07-03
`USING: accessors grouping kernel prettyprint sequencessequences.extras ; ! Like take-while, but for matrices and works from the rear.: take-col-while-last ( ... matrix quot: ( ... col -- ... ? ) -- ... new-matrix )    [ [ <reversed> ] map flip ] dip take-while ; inline : lcs ( seq -- lcs )    dup first swap [ all-equal? ] take-col-while-last to>> tail* ; { "baabababc" "baabc" "bbbabc" } lcs .{ "baabababc" "baabc" "bbbazc" } lcs .{ "" } lcs .`
Output:
```"abc"
"c"
""
```

## Go

Translation of: Wren
`package main import (    "fmt"    "strings") func lcs(a []string) string {    le := len(a)    if le == 0 {        return ""    }    if le == 1 {        return a    }    le0 := len(a)    minLen := le0    for i := 1; i < le; i++ {        if len(a[i]) < minLen {            minLen = len(a[i])        }    }    if minLen == 0 {        return ""    }    res := ""    a1 := a[1:]    for i := 1; i <= minLen; i++ {        suffix := a[le0-i:]        for _, e := range a1 {            if !strings.HasSuffix(e, suffix) {                return res            }        }        res = suffix    }    return res} func main() {    tests := [][]string{        {"baabababc", "baabc", "bbbabc"},        {"baabababc", "baabc", "bbbazc"},        {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"},        {"longest", "common", "suffix"},        {"suffix"},        {""},    }    for _, test := range tests {        fmt.Printf("%v -> \"%s\"\n", test, lcs(test))    }}`
Output:
```[baabababc baabc bbbabc] -> "abc"
[baabababc baabc bbbazc] -> "c"
[Sunday Monday Tuesday Wednesday Thursday Friday Saturday] -> "day"
[longest common suffix] -> ""
[suffix] -> "suffix"
[] -> ""
```

This task clearly needs a little more work to bring it up to the usual standard – it's rather underspecified, and bereft of test samples – but one response, for the moment, might be something like:

`import Data.List (transpose) longestCommonSuffix :: [String] -> StringlongestCommonSuffix =  foldr (flip (<>) . return . head) [] .  takeWhile (all =<< (==) . head) . transpose . fmap reverse main :: IO ()main =  mapM_    (putStrLn . longestCommonSuffix)    [ [ "Sunday"      , "Monday"      , "Tuesday"      , "Wednesday"      , "Thursday"      , "Friday"      , "Saturday"      ]    , [ "Sondag"      , "Maandag"      , "Dinsdag"      , "Woensdag"      , "Donderdag"      , "Vrydag"      , "Saterdag"      , "dag"      ]    ]`
Output:
```day
dag```

## JavaScript

`(() => {    'use strict';     // --------------- LONGEST COMMON SUFFIX ---------------     // longestCommonSuffix :: [String] -> String    const longestCommonSuffix = xs => (            1 < xs.length ? (                takeWhile(allSame)(                    transpose(xs.map(reverse))                ).map(fst).reverse()            ) : xs        ).join('');      // ----------------------- TEST ------------------------    const main = () =>        fTable('Longest common suffix:\n')(unwords)(            quoted("'")        )(longestCommonSuffix)([            'throne saxophone tone',            'prefix suffix infix',            'remark spark aardvark lark',            'ectoplasm banana brick'        ].map(words))      // ----------------- GENERIC FUNCTIONS -----------------     // allSame :: [a] -> Bool    const allSame = xs =>        2 > xs.length || (            h => xs.slice(1).every(x => h === x)        )(xs);      // fst :: (a, b) -> a    const fst = tpl =>        // First member of a pair.        tpl;      // fTable :: String -> (a -> String) ->     // (b -> String) -> (a -> b) -> [a] -> String    const fTable = s =>        // Heading -> x display function ->        //           fx display function ->        //    f -> values -> tabular string        xShow => fxShow => f => xs => {            const                ys = xs.map(xShow),                w = Math.max(...ys.map(length));            return s + '\n' + zipWith(                a => b => a.padStart(w, ' ') + ' -> ' + b            )(ys)(                xs.map(x => fxShow(f(x)))            ).join('\n');        };      // length :: [a] -> Int    const length = xs =>        // Returns Infinity over objects without finite        // length. This enables zip and zipWith to choose        // the shorter argument when one is non-finite,        // like cycle, repeat etc        'GeneratorFunction' !== xs.constructor        .constructor.name ? xs.length : Infinity;      // map :: (a -> b) -> [a] -> [b]    const map = f =>        // The list obtained by applying f        // to each element of xs.        // (The image of xs under f).        xs => [...xs].map(f);      // reverse :: [a] -> [a]    const reverse = xs =>        'string' !== typeof xs ? (            xs.slice(0).reverse()        ) : xs.split('').reverse().join('');      // str :: a -> String    const str = x =>        Array.isArray(x) && x.every(            v => ('string' === typeof v) && (1 === v.length)        ) ? (            x.join('')        ) : x.toString();      // take :: Int -> [a] -> [a]    // take :: Int -> String -> String    const take = n =>        // The first n elements of a list,        // string of characters, or stream.        xs => 'GeneratorFunction' !== xs        .constructor.constructor.name ? (            xs.slice(0, n)        ) : [].concat.apply([], Array.from({            length: n        }, () => {            const x = xs.next();            return x.done ? [] : [x.value];        }));      // takeWhile :: (a -> Bool) -> [a] -> [a]    // takeWhile :: (Char -> Bool) -> String -> String    const takeWhile = p =>        xs => (            n => xs.slice(                0, 0 < n ? until(                    i => n === i || !p(xs[i])                )(i => 1 + i)(0) : 0            )        )(xs.length);      // transpose :: [[a]] -> [[a]]    const transpose = xss => {        // If some of the rows are shorter than the following rows,         // their elements are skipped:        // > transpose [[10,11],,[],[30,31,32]] == [[10,20,30],[11,31],]        const go = xss =>            0 < xss.length ? (() => {                const                    h = xss,                    t = xss.slice(1);                return 0 < h.length ? [                    [h].concat(t.reduce(                        (a, xs) => a.concat(                            0 < xs.length ? (                                [xs]                            ) : []                        ),                        []                    ))                ].concat(go([h.slice(1)].concat(                    t.map(xs => xs.slice(1))                ))) : go(t);            })() : [];        return go(xss);    };      // until :: (a -> Bool) -> (a -> a) -> a -> a    const until = p => f => x => {        let v = x;        while (!p(v)) v = f(v);        return v;    };     // unwords :: [String] -> String    const unwords = xs =>        // A space-separated string derived        // from a list of words.        xs.join(' ');      // quoted :: Char -> String -> String    const quoted = c =>        // A string flanked on both sides        // by a specified quote character.        s => c + s + c;     // words :: String -> [String]    const words = s =>        // List of space-delimited sub-strings.        s.split(/\s+/);      // zipWithList :: (a -> b -> c) -> [a] -> [b] -> [c]    const zipWith = f =>        // A list constructed by zipping with a        // custom function, rather than with the        // default tuple constructor.        xs => ys => ((xs_, ys_) => {            const lng = Math.min(length(xs_), length(ys_));            return take(lng)(xs_).map(                (x, i) => f(x)(ys_[i])            );        })([...xs], [...ys]);     // MAIN ---    return main();})();`
Output:
```Longest common suffix:

throne saxophone tone -> 'one'
prefix suffix infix -> 'fix'
remark spark aardvark lark -> 'ark'
ectoplasm banana brick -> ''```

## Julia

`function longestcommonsuffix(strings)    n, nmax = 0, minimum(length, strings)    nmax == 0 && return ""    while n <= nmax && all(s -> s[end-n] == strings[end][end-n], strings)        n += 1    end    return strings[end-n+1:end]end println(longestcommonsuffix(["baabababc","baabc","bbbabc"]))println(longestcommonsuffix(["baabababc","baabc","bbbazc"]))println(longestcommonsuffix([""]))`
Output:
```abc
c

```

## Perl

Based on Longest_common_prefix Perl entry.

`use strict;use warnings;use feature 'say'; sub lcs {    for (0..\$#_) { \$_[\$_] = join '', reverse split '', \$_[\$_] }    join '', reverse split '', (join("\0", @_) =~ /^ ([^\0]*) [^\0]* (?:\0 \1 [^\0]*)* \$/sx);} for my \$words (  [ <Sunday Monday Tuesday Wednesday Thursday Friday Saturday> ],  [ <Sondag Maandag Dinsdag Woensdag Donderdag Vrydag Saterdag dag> ],  [ 2347, 9312347, 'acx5g2347', 12.02347 ],  [ <longest common suffix> ],  [ ('one, Hey!', 'three, Hey!', 'ale, Hey!', 'me, Hey!') ],  [ 'suffix' ],  [ '' ]) {    say qq{'@\$words' ==> '@{[lcs(@\$words)]}';}`
Output:
```'Sunday Monday Tuesday Wednesday Thursday Friday Saturday' ==> 'day'
'Sondag Maandag Dinsdag Woensdag Donderdag Vrydag Saterdag dag' ==> 'dag'
'2347 9312347 acx5g2347 12.02347' ==> '2347'
'longest common suffix' ==> ''
'one, Hey! three, Hey! ale, Hey! me, Hey!' ==> 'e, Hey!'
'suffix' ==> 'suffix'
'' ==> ''```

## Phix

Phix allows negative indexes, with -1 as the last element [same as \$], and -length(s) the first element of s, so we can just do this:

`function longestcommonsuffix(sequence strings)    string res = ""    if length(strings) then        res = strings        for i=2 to length(strings) do            string si = strings[i]            if length(si)<length(res) then                res = res[-length(si)..\$]            end if            for j=-1 to -length(res) by -1 do                if res[j]!=si[j] then                    res = res[j+1..\$]                    exit                end if            end for            if length(res)=0 then exit end if        end for    end if    return resend function sequence tests = {{"baabababc","baabc","bbbabc"},                  {"baabababc","baabc","bbbazc"},                  {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"},                  {"longest", "common", "suffix"},                  {"suffix"},                  {""}}for i=1 to length(tests) do    printf(1,"%v ==> \"%s\"\n",{tests[i],longestcommonsuffix(tests[i])})end for`
Output:
```{"baabababc","baabc","bbbabc"} ==> "abc"
{"baabababc","baabc","bbbazc"} ==> "c"
{"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"} ==> "day"
{"longest","common","suffix"} ==> ""
{"suffix"} ==> "suffix"
{""} ==> ""
```

## Python

Pending a fuller task statement and some test samples:

Works with: Python version 3
`'''Longest common suffix''' from itertools import takewhilefrom functools import reduce  # longestCommonSuffix :: [String] -> Stringdef longestCommonSuffix(xs):    '''Longest suffix shared by all       strings in xs.    '''    def allSame(cs):        h = cs        return all(h == c for c in cs[1:])     def firstCharPrepended(s, cs):        return cs + s    return reduce(        firstCharPrepended,        takewhile(            allSame,            zip(*(reversed(x) for x in xs))        ),        ''    )  # -------------------------- TEST --------------------------# main :: IO ()def main():    '''Test'''     samples = [        [            "Sunday", "Monday", "Tuesday", "Wednesday",            "Thursday", "Friday", "Saturday"        ], [            "Sondag", "Maandag", "Dinsdag", "Woensdag",            "Donderdag", "Vrydag", "Saterdag"        ]    ]    for xs in samples:        print(            longestCommonSuffix(xs)        )  # MAIN ---if __name__ == '__main__':    main()`
Output:
```day
dag```

## Raku

Works with: Rakudo version 2020.07
`sub longest-common-suffix ( *@words ) {    return '' unless [email protected]words;    my \$min = @words».chars.min;    for 1 .. * {        return @words.substr(* - \$min) if \$_ > \$min;        next if @words».substr(* - \$_).Set == 1;        return @words.substr(* - \$_ + 1);    }} say "{\$_.raku} - LCS: >{longest-common-suffix \$_}<" for  <Sunday Monday Tuesday Wednesday Thursday Friday Saturday>,  <Sondag Maandag Dinsdag Woensdag Donderdag Vrydag Saterdag dag>,  ( 2347, 9312347, 'acx5g2347', 12.02347 ),  <longest common suffix>,  ('one, Hey!', 'three, Hey!', 'ale, Hey!', 'me, Hey!'),  'suffix',  ''`
Output:
```("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday") - LCS: >day<
("Sondag", "Maandag", "Dinsdag", "Woensdag", "Donderdag", "Vrydag", "Saterdag", "dag") - LCS: >dag<
(2347, 9312347, "acx5g2347", 12.02347) - LCS: >2347<
("longest", "common", "suffix") - LCS: ><
("one, Hey!", "three, Hey!", "ale, Hey!", "me, Hey!") - LCS: >e, Hey!<
"suffix" - LCS: >suffix<
"" - LCS: ><```

## REXX

Essentially,   this REXX version simply reversed the strings,   and then finds the longest common  prefix.

`/*REXX program finds the  longest common suffix  contained in an array of strings.      */parse arg z;          z= space(z)                /*obtain optional arguments from the CL*/if z==''|z==","  then z='baabababc baabc bbbabc' /*Not specified?  Then use the default.*/z= space(z);      #= words(z)                    /*#:  the number of words in the list. */say 'There are '  #  " words in the list: "  zzr= reverse(z)                                   /*reverse Z, find longest common prefix*/@= word(zr, 1);       m= length(@)               /*get 1st word in reversed string; len.*/      do j=2  to #;    x= word(zr, j)             /*obtain a word (string) from the list.*/     t= compare(@, x)                            /*compare to the "base" word/string.   */     if t==1          then do;  @=;  leave       /*A mismatch of strings?   Then leave, */                           end                   /*no sense in comparing anymore strings*/     if t==0 & @==x   then t= length(@) + 1      /*Both strings equal?  Compute length. */     if t>=m  then iterate                       /*T ≥ M?  Then it's not longest string.*/     m= t - 1;        @= left(@, max(0, m) )     /*redefine max length & the base string*/     end   /*j*/say                                              /*stick a fork in it,  we're all done. */if m==0  then say 'There is no common suffix.'         else say 'The longest common suffix is: '   right( word(z, 1), m)`
output   when using the default input:
```There are  3  words in the list:  baabababc baabc bbbabc

The longest common suffix is:  abc
```

## Ring

` load "stdlib.ring" pre = ["baabababc","baabc","bbbabc"]len = len(pre)lenList = list(len)sub = list(len) see "Input:" + nlsee pre for n = 1 to len    temp = pre[n]    pre[n] = rever(temp)next for n = 1 to len    lenList[n] = len(pre[n])next lenList = sort(lenList)lenMax = lenList for m = 1 to lenMax      check = 0     sub1 = substr(pre,1,m)    sub2 = substr(pre,1,m)     sub3 = substr(pre,1,m)    if sub1 = sub2 and sub2 = sub3       check = 1    ok    if check = 1       longest = m    oknext longPrefix = substr(pre,1,longest)longPrefix = rever(longPrefix) see "Longest common suffix = " + longPrefix + nl func rever(cstr)     cStr2 = ""     for x = len(cStr) to 1 step -1          cStr2 = cStr2 + cStr[x]     next     return cStr2 `
Output:
```Input:
baabababc
baabc
bbbabc
Longest common suffix = abc
```

## Wren

`var lcs = Fn.new { |a|    if (a.count == 0) return ""    if (a.count == 1) return a    var minLen = a.reduce(a.count) { |min, s| (s.count < min) ? s.count : min }    if (minLen == 0) return ""    var res = ""    for (i in 1..minLen) {        var suffix = a[-i..-1]        for (e in a.skip(1)) {            if (!e.endsWith(suffix)) return res        }        res = suffix    }    return res} var tests = [    ["baabababc","baabc","bbbabc"],    ["baabababc","baabc","bbbazc"],    ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],    ["longest", "common", "suffix"],    ["suffix"],    [""]]for (test in tests) System.print("%(test) -> \"%(lcs.call(test))\"")`
Output:
```[baabababc, baabc, bbbabc] -> "abc"
[baabababc, baabc, bbbazc] -> "c"
[Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday] -> "day"
[longest, common, suffix] -> ""
[suffix] -> "suffix"
[] -> ""
```