Find common directory path: Difference between revisions

no edit summary
(→‎{{header|PowerShell}}: Version utilizing [Compare-Object](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/compare-object?view=powershell-6) PowerShell utility.)
No edit summary
(43 intermediate revisions by 24 users not shown)
Line 3:
 
Test your routine using the forward slash '/' character as the directory separator and the following three strings as input paths:
'/home/user1/tmp/coverage/test'
'/home/user1/tmp/covert/operator'
'/home/user1/tmp/coven/members'
 
Note: The resultant path should be the valid directory <code>'/home/user1/tmp'</code> and not the longest common string <code>'/home/user1/tmp/cove'</code>.
 
Note: The resultant path should be the valid directory <code>'/home/user1/tmp'</code> and not the longest common string <code>'/home/user1/tmp/cove'</code>.<br>
If your language has a routine that performs this function (even if it does not have a changeable separator character), then mention it as part of the task.
 
{{Template:Strings}}
 
;Related tasks
* [[Longest common prefix]]
 
<br><br>
 
=={{header|11l}}==
{{trans|C}}
 
<langsyntaxhighlight lang="11l">F find_common_directory_path(paths, sep = ‘/’)
V pos = 0
L
Line 35 ⟶ 34:
‘/home/user1/tmp/coverage/test’,
‘/home/user1/tmp/covert/operator’,
‘/home/user1/tmp/coven/members’]))</langsyntaxhighlight>
 
{{out}}
Line 43 ⟶ 42:
 
=={{header|Ada}}==
<langsyntaxhighlight lang="ada">
with Ada.Text_IO; use Ada.Text_IO;
 
Line 81 ⟶ 80:
);
end Test_Common_Path;
</syntaxhighlight>
</lang>
Output:
<pre>
Line 88 ⟶ 87:
 
=={{header|Aime}}==
<langsyntaxhighlight lang="aime">cdp(...)
{
integer e;
Line 112 ⟶ 111:
 
0;
}</langsyntaxhighlight>
 
=={{header|ALGOL 68}}==
Line 121 ⟶ 120:
{{works with|ELLA ALGOL 68|Any (with appropriate job cards) - tested with release [http://sourceforge.net/projects/algol68/files/algol68toc/algol68toc-1.8.8d/algol68toc-1.8-8d.fc9.i386.rpm/download 1.8-8d]}}
 
<langsyntaxhighlight lang="algol68"># Utilities code #
 
CHAR dir sep = "/"; # Assume POSIX #
Line 178 ⟶ 177:
);
print((dir name(common prefix(dir list)), new line))
)</langsyntaxhighlight>
Output:
<pre>
/home/user1/tmp
</pre>
 
=={{header|AppleScript}}==
<syntaxhighlight lang="applescript">on commonDirectoryPath(thePaths, separator)
set astid to AppleScript's text item delimiters
set AppleScript's text item delimiters to separator
set path1 to thePaths's beginning
set path1Components to path1's text items
set maxC to (count path1Components)
repeat with nextPath in (thePaths's rest)
if (maxC = 0) then exit repeat
set theseComponents to nextPath's text items
set componentCount to (count theseComponents)
if (componentCount < maxC) then set maxC to componentCount
repeat with c from 1 to maxC
if (theseComponents's item c ≠ path1Components's item c) then
set maxC to c - 1
exit repeat
end if
end repeat
end repeat
if (maxC > 0) then
set commonPath to path1's text 1 thru text item maxC
else
set commonPath to ""
end if
set AppleScript's text item delimiters to astid
return commonPath
end commonDirectoryPath
 
return commonDirectoryPath({"/home/user1/tmp/coverage/test", ¬
"/home/user1/tmp/covert/operator", ¬
"/home/user1/tmp/coven/members"}, "/")</syntaxhighlight>
 
{{output}}
<syntaxhighlight lang="applescript">"/home/user1/tmp"</syntaxhighlight>
 
=={{header|Arturo}}==
 
<syntaxhighlight lang="rebol">commonPathPrefix: function [lst][
paths: map lst => [split.by:"/" &]
 
common: new []
firstPath: first paths
loop .with:'i firstPath 'part [
found: true
loop paths 'p [
if part <> get p i [
found: false
break
]
]
if found -> 'common ++ part
]
return join.with:"/" common
]
 
print commonPathPrefix [
"/home/user1/tmp/coverage/test"
"/home/user1/tmp/covert/operator"
"/home/user1/tmp/coven/members"
]</syntaxhighlight>
 
{{out}}
 
<pre>/home/user1/tmp</pre>
 
=={{header|AutoHotkey}}==
<langsyntaxhighlight lang="autohotkey">Dir1 := "/home/user1/tmp/coverage/test"
Dir2 := "/home/user1/tmp/covert/operator"
Dir3 := "/home/user1/tmp/coven/members"
Line 199 ⟶ 264:
Else Break
 
MsgBox, % Result</langsyntaxhighlight>
Message box shows:
<pre>/home/user1/tmp</pre>
 
=={{header|AWK}}==
<langsyntaxhighlight lang="awk"># Finds the longest common directory of paths[1], paths[2], ...,
# paths[count], where sep is a single-character directory separator.
function common_dir(paths, count, sep, b, c, f, i, j, p) {
Line 244 ⟶ 309:
a[3] = "/home/user1/tmp/coven/members"
print common_dir(a, 3, "/")
}</langsyntaxhighlight>
 
Prints <tt>/home/user1/tmp</tt>.
Line 256 ⟶ 321:
Also, under FreeBASIC, the <code>pathSep</code> arg to <code>commonPath$</code> could be made optional, or even system-dependent.
 
<langsyntaxhighlight lang="qbasic">DECLARE FUNCTION commonPath$ (paths() AS STRING, pathSep AS STRING)
 
DATA "/home/user2", "/home/user1/tmp/covert/operator", "/home/user1/tmp/coven/members"
Line 307 ⟶ 372:
commonPath$ = tmpstr1
END IF
END FUNCTION</langsyntaxhighlight>
 
=={{header|BASIC256}}==
{{trans|GW-BASIC}}
<syntaxhighlight lang="basic256">x = "/home/user1/tmp/coverage/test"
y = "/home/user1/tmp/covert/operator"
z = "/home/user1/tmp/coven/members"
 
a = length(x)
if a > length(y) then a = length(y)
if a > length(z) then a = length(z)
for i = 1 to a
if mid(x, i, 1) <> mid(y, i, 1) then exit for
next i
a = i - 1
 
for i = 1 to a
if mid(x, i, 1) <> mid(z, i, 1) then exit for
next i
a = i - 1
 
if mid(x, i, 1) <> "/" then
for i = a to 1 step -1
if "/" = mid(x, i, 1) then exit for
next i
end if
 
REM Task description says no trailing slash, so...
a = i - 1
print "Common path is '"; left(x, a); "'"</syntaxhighlight>
 
=={{header|Batch File}}==
<langsyntaxhighlight lang="dos">
@echo off
setlocal enabledelayedexpansion
Line 372 ⟶ 466:
endlocal
exit /b
</syntaxhighlight>
</lang>
{{out}}
<pre>
/home/user1/tmp/
</pre>
 
 
=={{header|BBC BASIC}}==
<langsyntaxhighlight lang="bbcbasic"> DIM path$(3)
path$(1) = "/home/user1/tmp/coverage/test"
Line 398 ⟶ 491:
NEXT J%
UNTIL I% = 0
= LEFT$(p$(1), O%-1)</langsyntaxhighlight>
 
=={{header|C}}==
<langsyntaxhighlight Clang="c">#include <stdio.h>
 
int common_len(const char *const *names, int n, char sep)
Line 434 ⟶ 527:
 
return 0;
}</langsyntaxhighlight>output:<syntaxhighlight lang="text">Common path: /home/user1/tmp</langsyntaxhighlight>
 
=={{header|C++}}==
<lang cpp>#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
 
std::string longestPath( const std::vector<std::string> & , char ) ;
 
int main( ) {
std::string dirs[ ] = {
"/home/user1/tmp/coverage/test" ,
"/home/user1/tmp/covert/operator" ,
"/home/user1/tmp/coven/members" } ;
std::vector<std::string> myDirs ( dirs , dirs + 3 ) ;
std::cout << "The longest common path of the given directories is "
<< longestPath( myDirs , '/' ) << "!\n" ;
return 0 ;
}
 
std::string longestPath( const std::vector<std::string> & dirs , char separator ) {
std::vector<std::string>::const_iterator vsi = dirs.begin( ) ;
int maxCharactersCommon = vsi->length( ) ;
std::string compareString = *vsi ;
for ( vsi = dirs.begin( ) + 1 ; vsi != dirs.end( ) ; vsi++ ) {
std::pair<std::string::const_iterator , std::string::const_iterator> p =
std::mismatch( compareString.begin( ) , compareString.end( ) , vsi->begin( ) ) ;
if (( p.first - compareString.begin( ) ) < maxCharactersCommon )
maxCharactersCommon = p.first - compareString.begin( ) ;
}
std::string::size_type found = compareString.rfind( separator , maxCharactersCommon ) ;
return compareString.substr( 0 , found ) ;
}</lang>
Output:
<pre>
The longest common path of the given directories is /home/user1/tmp!
</pre>
 
=={{header|Clojure}}==
<lang clojure>(use '[clojure.string :only [join,split]])
 
(defn common-prefix [sep paths]
(let [parts-per-path (map #(split % (re-pattern sep)) paths)
parts-per-position (apply map vector parts-per-path)]
(join sep
(for [parts parts-per-position :while (apply = parts)]
(first parts)))))
 
(println
(common-prefix "/"
["/home/user1/tmp/coverage/test"
"/home/user1/tmp/covert/operator"
"/home/user1/tmp/coven/members"]))</lang>
 
=={{header|C sharp|C#}}==
 
<langsyntaxhighlight lang="csharp">
using System;
using System.Collections.Generic;
Line 555 ⟶ 595:
}
 
</syntaxhighlight>
</lang>
 
=={{header|C++}}==
<syntaxhighlight lang="cpp">#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
 
std::string longestPath( const std::vector<std::string> & , char ) ;
 
int main( ) {
std::string dirs[ ] = {
"/home/user1/tmp/coverage/test" ,
"/home/user1/tmp/covert/operator" ,
"/home/user1/tmp/coven/members" } ;
std::vector<std::string> myDirs ( dirs , dirs + 3 ) ;
std::cout << "The longest common path of the given directories is "
<< longestPath( myDirs , '/' ) << "!\n" ;
return 0 ;
}
 
std::string longestPath( const std::vector<std::string> & dirs , char separator ) {
std::vector<std::string>::const_iterator vsi = dirs.begin( ) ;
int maxCharactersCommon = vsi->length( ) ;
std::string compareString = *vsi ;
for ( vsi = dirs.begin( ) + 1 ; vsi != dirs.end( ) ; vsi++ ) {
std::pair<std::string::const_iterator , std::string::const_iterator> p =
std::mismatch( compareString.begin( ) , compareString.end( ) , vsi->begin( ) ) ;
if (( p.first - compareString.begin( ) ) < maxCharactersCommon )
maxCharactersCommon = p.first - compareString.begin( ) ;
}
std::string::size_type found = compareString.rfind( separator , maxCharactersCommon ) ;
return compareString.substr( 0 , found ) ;
}</syntaxhighlight>
Output:
<pre>
The longest common path of the given directories is /home/user1/tmp!
</pre>
 
=={{header|Clojure}}==
<syntaxhighlight lang="clojure">(use '[clojure.string :only [join,split]])
 
(defn common-prefix [sep paths]
(let [parts-per-path (map #(split % (re-pattern sep)) paths)
parts-per-position (apply map vector parts-per-path)]
(join sep
(for [parts parts-per-position :while (apply = parts)]
(first parts)))))
 
(println
(common-prefix "/"
["/home/user1/tmp/coverage/test"
"/home/user1/tmp/covert/operator"
"/home/user1/tmp/coven/members"]))</syntaxhighlight>
 
 
=={{header|Common Lisp}}==
The strings represent file paths, so instead of treating them as simple strings, this uses the specialized pathname functions, which are more robust and generic.
<syntaxhighlight lang="lisp">
(defun common-directory-path (&rest paths)
(do* ((pathnames (mapcar #'(lambda (path) (cdr (pathname-directory (pathname path)))) paths)) ; convert strings to lists of subdirectories
(rem pathnames (cdr rem))
(pos (length (first rem))) ) ; position of first mismatched element
((null (cdr rem)) (make-pathname :directory (cons :absolute (subseq (first pathnames) 0 pos)))) ; take the common sublists and convert back to a pathname
(setq pos (min pos (mismatch (first rem) (second rem) :test #'string-equal))) )) ; compare two paths
</syntaxhighlight>
 
 
{{out}}
<pre>(common-directory-path "/home/user1/tmp/coverage/test" "/home/user1/tmp/covert/operator" "/home/user1/tmp/coven/members")
==> #P"/home/user1/tmp/"</pre>
 
=={{header|D}}==
This code uses the std.algorithm.commonPrefix function that finds the common prefix of two ranges.
<langsyntaxhighlight lang="d">import std.stdio, std.string, std.algorithm, std.path, std.array;
 
string commonDirPath(in string[] paths, in string sep = "/") pure {
Line 572 ⟶ 682:
"/home/user1/tmp/coven/members"];
writeln(`The common path is: "`, paths.commonDirPath, '"');
}</langsyntaxhighlight>
{{out}}
<pre>The common path is: "/home/user1/tmp"</pre>
=={{header|Delphi}}==
{{libheader| System.SysUtils}}
<syntaxhighlight lang="delphi">
program Find_common_directory_path;
 
{$APPTYPE CONSOLE}
 
uses
System.SysUtils;
 
function FindCommonPath(Separator: Char; Paths: TArray<string>): string;
var
SeparatedPath: array of TArray<string>;
minLength, index: Integer;
isSame: Boolean;
j, i: Integer;
cmp: string;
begin
SetLength(SeparatedPath, length(Paths));
minLength := MaxInt;
for i := 0 to High(SeparatedPath) do
begin
SeparatedPath[i] := Paths[i].Split([Separator]);
if minLength > length(SeparatedPath[i]) then
minLength := length(SeparatedPath[i]);
end;
 
index := -1;
 
for i := 0 to minLength - 1 do
begin
isSame := True;
cmp := SeparatedPath[0][i];
for j := 1 to High(SeparatedPath) do
if SeparatedPath[j][i] <> cmp then
begin
isSame := False;
Break;
end;
if not isSame then
begin
index := i - 1;
Break;
end;
end;
 
Result := '';
if index >= 0 then
for i := 0 to index do
begin
Result := Result + SeparatedPath[0][i];
if i < index then
Result := Result + Separator;
end;
end;
 
begin
Writeln(FindCommonPath('/', [
'/home/user1/tmp/coverage/test',
'/home/user1/tmp/covert/operator',
'/home/user1/tmp/coven/members']));
Readln;
end.</syntaxhighlight>
{{out}}
<pre>/home/user1/tmp</pre>
 
=={{header|EasyLang}}==
{{trans|AWK}}
 
<syntaxhighlight lang=easylang>
func$ comdir path$[] .
for i = 1 to len path$[1]
c$ = substr path$[1] i 1
for j = 2 to len path$[]
if c$ <> substr path$[j] i 1
break 2
.
.
if c$ = "/"
f = i - 1
.
.
return substr path$[1] 1 f
.
a$[] &= "/home/user1/tmp/coverage/test"
a$[] &= "/home/user1/tmp/covert/operator"
a$[] &= "/home/user1/tmp/coven/members"
print comdir a$[]
</syntaxhighlight>
 
=={{header|Elixir}}==
{{trans|Ruby}}
<langsyntaxhighlight lang="elixir">defmodule RC do
def common_directory_path(dirs, separator \\ "/") do
dir1 = Enum.min(dirs) |> String.split(separator)
Line 588 ⟶ 787:
 
dirs = ~w( /home/user1/tmp/coverage/test /home/user1/tmp/covert/operator /home/user1/tmp/coven/members )
IO.inspect RC.common_directory_path(dirs)</langsyntaxhighlight>
 
{{out}}
Line 596 ⟶ 795:
 
=={{header|Erlang}}==
<syntaxhighlight lang="erlang">
<lang Erlang>
-module( find_common_directory ).
 
Line 608 ⟶ 807:
 
keep_common( Components, Acc ) -> [X || X <- Components, Y <- Acc, X =:= Y].
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 616 ⟶ 815:
 
=={{header|F_Sharp|F#}}==
<langsyntaxhighlight lang="fsharp">open System
 
let (|SeqNode|SeqEmpty|) s =
Line 645 ⟶ 844:
 
printfn "The common preffix is: %A" (String.Join("/", (commonPrefix args)))
0</langsyntaxhighlight>
Output for the given task input
<pre>The common preffix is: "/home/user1/tmp"</pre>
 
=={{header|Factor}}==
<langsyntaxhighlight lang="factor">: take-shorter ( seq1 seq2 -- shorter )
[ shorter? ] 2keep ? ;
 
Line 660 ⟶ 859:
 
: common-prefix ( seq separator -- prefix )
[ ] swap '[ _ common-prefix-1 ] map-reduce ;</langsyntaxhighlight>
 
( scratchpad ) {
Line 671 ⟶ 870:
=={{header|FreeBASIC}}==
{{Trans|Visual Basic}}
<langsyntaxhighlight lang="freebasic">
' compile: fbc.exe -s console cdp.bas
 
Line 736 ⟶ 935:
Print : Print "hit any key to end program"
Sleep
End</langsyntaxhighlight>
{{out}}
<pre>/home/user1/tmp/coverage/test
Line 753 ⟶ 952:
/home/user1/tmp/coven/members
/ <- common</pre>
 
=={{header|FutureBasic}}==
<syntaxhighlight lang="futurebasic">
include "NSLog.incl"
 
local fn FindCommonDirectoryPath
CFArrayRef path1 = fn StringComponentsSeparatedByString( @"/home/user1/tmp/coverage/test", @"/" )
CFArrayRef path2 = fn StringComponentsSeparatedByString( @"/home/user1/tmp/covert/operator", @"/" )
CFArrayRef path3 = fn StringComponentsSeparatedByString( @"/home/user1/tmp/coven/members", @"/" )
long i, count = fn ArrayCount( path1 )
CFMutableStringRef mutStr = fn MutableStringWithCapacity( 0 )
for i = 0 to count - 1
if ( fn StringIsEqual( path1[i], path2[i] ) ) and ( fn StringIsEqual( path2[i], path3[i] ) )
MutableStringAppendString( mutStr, fn StringWithFormat( @"%@/\b", path1[i] ) )
else
exit for
end if
next
NSLog( @"%@", mutstr )
end fn
 
fn FindCommonDirectoryPath
 
HandleEvents
</syntaxhighlight>
{{output}}
<pre>
/home/user1/tmp/
</pre>
 
=={{header|Gambas}}==
<langsyntaxhighlight lang="gambas">Public Sub Main()
Dim sFolder As String[] = ["/home/user1/tmp/coverage/test", "/home/user1/tmp/covert/operator", "/home/user1/tmp/coven/members"]
Dim sSame As String
Line 771 ⟶ 1,000:
Print Mid(sSame, 1, RInStr(sSame, "/") - 1)
 
End</langsyntaxhighlight>
Output:
<pre>
Line 782 ⟶ 1,011:
E.g. (<code>/home/user1, /home/user1/foo, /home/user1/bar</code>) should result in <code>/home/user1</code>, not <code>/home</code>.
 
<langsyntaxhighlight lang="go">package main
 
import (
Line 860 ⟶ 1,089:
fmt.Println("Common path:", c)
}
}</langsyntaxhighlight>
 
=={{header|Groovy}}==
Solution:
<langsyntaxhighlight lang="groovy">def commonPath = { delim, Object[] paths ->
def pathParts = paths.collect { it.split(delim) }
pathParts.transpose().inject([match:true, commonParts:[]]) { aggregator, part ->
Line 871 ⟶ 1,100:
aggregator
}.commonParts.join(delim)
}</langsyntaxhighlight>
 
Test:
<langsyntaxhighlight lang="groovy">println commonPath('/',
'/home/user1/tmp/coverage/test',
'/home/user1/tmp/covert/operator',
Line 883 ⟶ 1,112:
'/home/user1/tmp/covert/test',
'/home/user1/tmp/coven/test',
'/home/user1/tmp/covers/test')</langsyntaxhighlight>
 
Output:
Line 892 ⟶ 1,121:
{{works with|GW-BASIC}}
{{works with|Chipmunk Basic}}
{{works with|QBasic}}
 
Because most BASICs don't have any sort of parsing functions built in, we have to deal with the entire string (rather than checking one level at a time).
Line 897 ⟶ 1,127:
Note that if the root directory is the common path, this reports the same as no match found (i.e. blank result).
 
<langsyntaxhighlight lang="qbasic">10 REM All GOTO statements can be replaced with EXIT FOR in newer BASICs.
 
110 X$ = "/home/user1/tmp/coverage/test"
Line 925 ⟶ 1,155:
350 A = L0 - 1
360 P$ = LEFT$(X$, A)
370 PRINT "Common path is '"; P$; "'"</langsyntaxhighlight>
 
Output:
Line 932 ⟶ 1,162:
=={{header|Haskell}}==
 
<langsyntaxhighlight lang="haskell">import Data.List
 
-- Return the common prefix of two lists.
Line 954 ⟶ 1,184:
"/home/user1/tmp/covert/operator",
"/home/user1/tmp/coven/members"
]</langsyntaxhighlight>
 
Or, expressed directly in applicative terms:
Or perhaps:
<langsyntaxhighlight lang="haskell">import Data.List (transpose, intercalate)
import Data.List.Split (splitOn)
 
cdp :: [String] -> String
cdp xs
| null xs = []
| otherwise =
(intercalate "/" .
fmap head . takeWhile same . transpose . fmap (splitOn "/"))
xs
 
------------------ COMMON DIRECTORY PATH -----------------
same
 
:: Eq a
commonDirectoryPath :: [String] -> String
=> [a] -> Bool
samecommonDirectoryPath [] = True[]
commonDirectoryPath xs =
same (x:xs) = all (x ==) xs
intercalate "/" $
head <$> takeWhile ((all . (==) . head) <*> tail) $
transpose (splitOn "/" <$> xs)
 
--------------------------- TEST -------------------------
main :: IO ()
main =
(putStrLn . cdpcommonDirectoryPath)
[ "/home/user1/tmp/coverage/test"
, "/home/user1/tmp/covert/operator"
, "/home/user1/tmp/coven/members"
]</langsyntaxhighlight>
{{Out}}
<pre>/home/user1/tmp</pre>
 
=={{header|HicEst}}==
<langsyntaxhighlight HicEstlang="hicest">CHARACTER a='/home/user1/tmp/coverage/test', b='/home/user1/tmp/covert/operator', c='/home/user1/tmp/coven/members'
 
minLength = MIN( LEN(a), LEN(b), LEN(c) )
Line 998 ⟶ 1,225:
WRITE(Messagebox, Name) "No common directory for", a, b, c
ENDIF
ENDDO</langsyntaxhighlight>
 
=={{header|Icon}} and {{header|Unicon}}==
<langsyntaxhighlight Iconlang="icon">procedure main()
write(lcdsubstr(["/home/user1/tmp/coverage/test","/home/user1/tmp/covert/operator","/home/user1/tmp/coven/members"]))
end
Line 1,020 ⟶ 1,247:
if not match(s,x) then fail
return s
end</langsyntaxhighlight>
 
=={{header|J}}==
'''Solution:'''
<langsyntaxhighlight lang="j">parseDirs =: = <;.2 ]
getCommonPrefix =: {. ;@{.~ 0 i.~ *./@(="1 {.)
 
getCommonDirPath=: [: getCommonPrefix parseDirs&></langsyntaxhighlight>
 
'''Example:'''
<langsyntaxhighlight lang="j"> paths=: '/home/user1/tmp/coverage/test';'/home/user1/tmp/covert/operator';'/home/user1/tmp/coven/members'
getCommonPrefix >paths
/home/user1/tmp/cove
'/' getCommonDirPath paths
/home/user1/tmp/</langsyntaxhighlight>
 
'''Note:'''
This alternative formulation of parseDirs provides cross-platform support, without the need to specify the path separator.
<langsyntaxhighlight lang="j">parseDirs =: (PATHSEP_j_&= <;.2 ])@jhostpath</langsyntaxhighlight>
 
=={{header|Java}}==
{{works with|Java|1.5+}}
This example is case-sensitive.
<langsyntaxhighlight lang="java5">public class CommonPath {
public static String commonPath(String... paths){
String commonPath = "";
Line 1,080 ⟶ 1,308:
System.out.println(commonPath(paths2));
}
}</langsyntaxhighlight>
Output:
<pre>/home/user1/tmp/
Line 1,087 ⟶ 1,315:
 
A slightly modified version of the previous program, only the method commonPath() is changed.
<langsyntaxhighlight lang="java5">
static String commonPath(String... paths){
String commonPath = "";
Line 1,106 ⟶ 1,334:
return commonPath;
}
</syntaxhighlight>
</lang>
 
=={{header|JavaScript}}==
<langsyntaxhighlight lang="javascript">
/**
* Given an array of strings, return an array of arrays, containing the
Line 1,155 ⟶ 1,383:
 
console.log(`Common path is: ${commonPath(cdpInput)}`);
</syntaxhighlight>
</lang>
 
{{out}}
Line 1,161 ⟶ 1,389:
Common path is: /home/user1/tmp
</pre>
 
 
=={{header|jq}}==
<langsyntaxhighlight lang="jq"># maximal_initial_subarray takes as input an array of arrays:
def maximal_initial_subarray:
(map( .[0] ) | unique) as $u
Line 1,177 ⟶ 1,404:
[.[] | split(slash)] | maximal_initial_subarray | join(slash) ;
 
common_path("/")</langsyntaxhighlight>
 
Assuming the above jq program is in a file named common_path.jq and that the file directories.txt contains the three given directory strings quoted with double quotation marks:
<langsyntaxhighlight lang="jq">$ jq -s -f common_path.jq directories.txt
"home/user1/tmp"</langsyntaxhighlight>
 
=={{header|Julia}}==
{{works with|Julia|0.6}}
 
<langsyntaxhighlight lang="julia">function commonpath(ds::Vector{<:AbstractString}, dlm::Char='/')
0 < length(ds) || return ""
1 < length(ds) || return String(ds[1])
Line 1,205 ⟶ 1,432:
 
println("Comparing:\n - ", join(test, "\n - "))
println("for their common directory path yields:\n", commonpath(test))</langsyntaxhighlight>
 
{{out}}
Line 1,216 ⟶ 1,443:
 
=={{header|Kotlin}}==
<langsyntaxhighlight lang="scala">// version 1.1.51
 
fun findCommonDirPath(paths: List<String>, separator: Char): String {
Line 1,243 ⟶ 1,470:
println("The common directory path of:\n\n$pathsToPrint\n")
println("is '${findCommonDirPath(paths, '/')}'")
}</langsyntaxhighlight>
 
{{out}}
Line 1,257 ⟶ 1,484:
 
=={{header|Lasso}}==
<langsyntaxhighlight Lassolang="lasso">#!/usr/bin/lasso9
 
local(
Line 1,273 ⟶ 1,500:
}
 
stdoutnl(commonpath(#path1, #path2, #path3))</langsyntaxhighlight>
 
Output:
Line 1,279 ⟶ 1,506:
 
=={{header|Liberty BASIC}}==
<langsyntaxhighlight lang="lb">path$(1) = "/home/user1/tmp/coverage/test"
path$(2) = "/home/user1/tmp/covert/operator"
path$(3) = "/home/user1/tmp/coven/members"
Line 1,303 ⟶ 1,530:
end if
wend
end function</langsyntaxhighlight>
 
=={{header|Lingo}}==
<langsyntaxhighlight lang="lingo">on getCommonPath (pathes, sep)
_player.itemDelimiter = sep
 
Line 1,324 ⟶ 1,551:
end repeat
return pathes[1].item[1..commonCnt]
end</langsyntaxhighlight>
<langsyntaxhighlight lang="lingo">pathes = []
pathes.add("/home/user1/tmp/coverage/test")
pathes.add("/home/user1/tmp/covert/operator")
Line 1,331 ⟶ 1,558:
 
put getCommonPath(pathes, "/")
-- "/home/user1/tmp"</langsyntaxhighlight>
 
=={{header|MapBasic}}==
Line 1,337 ⟶ 1,564:
Derived from the [https://www.rosettacode.org/wiki/Find_common_directory_path#BASIC BASIC] example above
 
<langsyntaxhighlight lang="qbasic">Include "MapBasic.def"
 
Declare Sub Main
Line 1,402 ⟶ 1,629:
PRINT "Common path is " + commonPath(x(), Sep)
 
End Sub</langsyntaxhighlight>
 
=={{header|Maple}}==
<syntaxhighlight lang="maple">
<lang Maple>
dirpath:=proc(a,b,c)
local dirtemp,dirnew,x;
Line 1,415 ⟶ 1,642:
end use;
end proc;
</syntaxhighlight>
</lang>
 
=={{header|Mathematica}}/{{header|Wolfram Language}}==
<langsyntaxhighlight Mathematicalang="mathematica">FindCommonDirectory[x_] := If[StringTake[#, -1] != "/", StringTake[#, Max[StringPosition[#, "/"]]], #] &
[Fold[LongestCommonSubsequence, First[x] , Rest[x]]]
 
FindCommonDirectory[{"/home/user1/tmp/coverage/test", "/home/user1/tmp/covert/operator", "/home/user1/tmp/coven/members"}]
->"/home/user1/tmp/"</langsyntaxhighlight>
 
=={{header|MATLAB}} / {{header|Octave}}==
<syntaxhighlight lang="matlab">
function lcp = longest_common_dirpath(varargin)
ix = find(varargin{1}=='/');
ca = char(varargin);
flag = all(ca==ca(1,:),1);
for k = length(ix):-1:1,
if all(flag(1:ix(k))); break; end
end
lcp = ca(1,1:ix(k));
end
 
longest_common_dirpath('/home/user1/tmp/coverage/test', '/home/user1/tmp/covert/operator', '/home/user1/tmp/coven/members')
</syntaxhighlight>
 
{{out}}
<pre>
ans = /home/user1/tmp/
</pre>
 
=={{header|Maxima}}==
<langsyntaxhighlight lang="maxima">scommon(a, b) := block([n: min(slength(a), slength(b))],
substring(a, 1, catch(for i thru n do (
if not cequal(charat(a, i), charat(b, i)) then throw(i)), n + 1)))$
Line 1,435 ⟶ 1,682:
 
commonpath(["c:/files/banister.jpg", "c:/files/bank.xls", "c:/files/banana-recipes.txt"]);
"c:/files"</langsyntaxhighlight>
 
=={{header|MUMPS}}==
<syntaxhighlight lang="mumps">FCD
<lang MUMPS>FCD
NEW D,SEP,EQ,LONG,DONE,I,J,K,RETURN
SET D(1)="/home/user1/tmp/coverage/test"
Line 1,452 ⟶ 1,699:
WRITE !,"The longest common directory is: ",RETURN
KILL D,SEP,EQ,LONG,DONE,I,J,K,RETURN
QUIT</langsyntaxhighlight>
Usage:<pre>
USER>D FCD^ROSETTA
Line 1,463 ⟶ 1,710:
 
=={{header|Nim}}==
<langsyntaxhighlight lang="nim">import strutils
 
proc commonprefix(paths: openarray[string], sep = "/"): string =
if paths.len == 0: return ""
block outer:
for i in 0 ..< paths[0].len:
result = paths[0][0 .. i]
for path in paths:
if not path.startsWith(result):
break outer
result = result[0 .. <result.rfind(sep)]
 
echo commonprefix(@["/home/user1/tmp/coverage/test", "/home/user1/tmp/covert/operator", "/home/user1/tmp/coven/members"])</langsyntaxhighlight>
Output:
<pre>/home/user1/tmp</pre>
 
=={{header|OCaml}}==
<syntaxhighlight lang="ocaml">let rec common_prefix xs ys = match xs, ys with
| x :: xs, y :: ys when x = y -> x :: common_prefix xs ys
| _ -> []
 
let common_prefix_all = function
<lang ocaml>let rec aux acc paths =
| x :: xs -> List.fold_left common_prefix x xs
if List.mem [] paths
| _ -> []
then (List.rev acc) else
let heads = List.map List.hd paths in
let item = List.hd heads in
let all_the_same =
List.for_all ((=) item) (List.tl heads)
in
if all_the_same
then aux (item::acc) (List.map List.tl paths)
else (List.rev acc)
 
let common_prefixcommon_ancestor ~sep =paths function=
List.map Str.(split_delim (regexp_string sep)) paths
| [] -> invalid_arg "common_prefix"
|> common_prefix_all
| dirs ->
|> String.concat sep
let paths = List.map (Str.split (Str.regexp_string sep)) dirs in
let res = aux [] paths in
(sep ^ (String.concat sep res))
 
let ()_ = assert begin
common_ancestor ~sep:"/" [
let dirs = [
"/home/user1/tmp/coverage/test";
"/home/user1/tmp/covert/operator";
"/home/user1/tmp/coven/members";
] = "/home/user1/tmp"
] in
end</syntaxhighlight>
print_endline (common_prefix "/" dirs);
;;</lang>
 
(usesRequires the modulestandard <code>[httphttps://camlocaml.inria.fr/pub/docsorg/manual-ocaml/libref/Strlibstr.html Strstr]</code>, str.cma)library
 
=={{header|OpenEdge/Progress}}==
<langsyntaxhighlight lang="progress">FUNCTION findCommonDir RETURNS CHAR(
i_cdirs AS CHAR,
i_cseparator AS CHAR
Line 1,542 ⟶ 1,781:
RETURN cresult.
 
END FUNCTION.</langsyntaxhighlight>
 
<langsyntaxhighlight lang="progress">MESSAGE
findCommonDir(
'/home/user1/tmp/coverage/test' + '~n' +
Line 1,551 ⟶ 1,790:
'/'
)
VIEW-AS ALERT-BOX</langsyntaxhighlight>
 
Output
Line 1,565 ⟶ 1,804:
=={{header|Oz}}==
With a few helper functions, we can express the solution like this in Oz:
<langsyntaxhighlight lang="oz">declare
fun {CommonPrefix Sep Paths}
fun {GetParts P} {String.tokens P Sep} end
Line 1,596 ⟶ 1,835:
["/home/user1/tmp/coverage/test"
"/home/user1/tmp/covert/operator"
"/home/user1/tmp/coven/members"]}}</langsyntaxhighlight>
 
=={{header|PARI/GP}}==
<langsyntaxhighlight lang="parigp">cdp(v)={
my(s="");
v=apply(t->Vec(t),v);
Line 1,610 ⟶ 1,849:
if(vecmax(apply(length,v))==vecmin(apply(length,v)),concat(v[1]),s)
};
cdp(["/home/user1/tmp/coverage/test","/home/user1/tmp/covert/operator","/home/user1/tmp/coven/members"])</langsyntaxhighlight>
 
=={{header|Pascal}}==
==={{header|Free Pascal}}===
<syntaxhighlight lang="pascal">
Program CommonPaths;
{$mode ObjFPC}{$H+}
uses
Classes, Math;
 
const
Paths: array of string = ('/home/user1/tmp/coverage/test',
'/home/user1/tmp/covert/operator',
'/home/user1/tmp/coven/members');
 
function FindShortestCommonPath(arr: array of TStringList; shortestPath: Integer): string;
var
i, j: Integer;
commonStr: string;
begin
Result := '/';
if Length(arr) = 0 then
Exit;
for j := 0 to shortestPath - 1 do
begin
commonStr := arr[0][j];
for i := 1 to High(arr) do
begin
if arr[i][j] <> commonStr then
Exit(Result);
end;
Result := Result + commonStr + '/';
end;
end;
var
arr: array of TStringList;
i, shortestpath: uint32;
 
begin
shortestpath := High(uint32);
SetLength(arr, Length(paths));
 
for i := 0 to High(paths) do
begin
arr[i] := TStringList.Create;
arr[i].AddDelimitedText(paths[i], '/', false);
arr[i].Delete(0);
shortestpath := Min(shortestpath, arr[i].Count);
end;
 
Writeln(FindShortestCommonPath(arr, shortestpath));
 
for i := 0 to High(paths) do
arr[i].Free;
end.
</syntaxhighlight>
{{out}}
<pre>
/home/user1/tmp/
</pre>
 
 
 
 
=={{header|Perl}}==
Line 1,616 ⟶ 1,917:
A solution which lets the regex engine do all the work ''(it operates on the concatenation of the given paths delimited by null-bytes, which should be safe since null-bytes are not allowed inside paths)'':
 
<langsyntaxhighlight Perllang="perl">sub common_prefix {
my $sep = shift;
my $paths = join "\0", map { $_.$sep } @_;
$paths =~ /^ ( [^\0]* ) $sep [^\0]* (?: \0 \1 $sep [^\0]* )* $/x;
return $1;
}</langsyntaxhighlight>
 
A more conventional solution, which tallies up all potential prefixes from the given paths and then looks for the longest one that occurred the same number of times as there are paths:
 
<langsyntaxhighlight Perllang="perl">use List::Util qw(first);
 
sub common_prefix {
Line 1,636 ⟶ 1,937:
return first { $prefixes{$_} == @paths } reverse sort keys %prefixes;
}</langsyntaxhighlight>
 
'''Testing:'''
 
<langsyntaxhighlight lang="perl">my @paths = qw(/home/user1/tmp/coverage/test
/home/user1/tmp/covert/operator
/home/user1/tmp/coven/members);
print common_prefix('/', @paths), "\n";</langsyntaxhighlight>
 
{{out}}
<pre>/home/user1/tmp</pre>
 
=={{header|Perl 6}}==
<lang Perl 6>my $sep = '/';
my @dirs = </home/user1/tmp/coverage/test
/home/user1/tmp/covert/operator
/home/user1/tmp/coven/members>;
 
my @comps = @dirs.map: { [ .comb(/ $sep [ <!before $sep> . ]* /) ] };
 
my $prefix = '';
 
while all(@comps[*]»[0]) eq @comps[0][0] {
$prefix ~= @comps[0][0] // last;
@comps».shift;
}
 
say "The longest common path is $prefix";
</lang>
Output:
<pre>
The longest common path is /home/user1/tmp
</pre>
If you'd prefer a pure FP solution without side effects, you can use this:
<lang perl6>my $sep := '/';
my @dirs := </home/user1/tmp/coverage/test
/home/user1/tmp/covert/operator
/home/user1/tmp/coven/members>;
 
my @comps = @dirs.map: { [ .comb(/ $sep [ <!before $sep> . ]* /) ] };
 
say "The longest common path is ",
gather for 0..* -> $column {
last unless all(@comps[*]»[$column]) eq @comps[0][$column];
take @comps[0][$column] // last;
}</lang>
Or here's another factoring, that focuses on building the result with cumulative sequences and getting the solution with `first`:
<lang perl6>my $sep = '/';
my @dirs = </home/user1/tmp/coverage/test
/home/user1/tmp/covert/operator
/home/user1/tmp/coven/members>;
 
sub is_common_prefix { so $^prefix eq all(@dirs).substr(0, $prefix.chars) }
 
say ([\~] @dirs.comb(/ $sep [ <!before $sep> . ]* /)).reverse.first: &is_common_prefix</lang>
 
=={{header|Phix}}==
Note: if the testset contains /home/user1/tmp the result is /home/user1, with /home/user1/tmp/ instead of that, it is /home/user1/tmp<br>
To change that behaviour, simply remove both the [1..-2]<br>
For cross-platform operation, simply use the split_path and join_path builtins (not pwa/p2js compatible) instead of split and join.
<!--<syntaxhighlight lang="phix">(phixonline)-->
<lang Phix>function common_directory_path(sequence paths, integer sep='/')
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
sequence res = {}
<span style="color: #008080;">function</span> <span style="color: #000000;">common_directory_path</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">paths</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">sep</span><span style="color: #0000FF;">=</span><span style="color: #008000;">'/'</span><span style="color: #0000FF;">)</span>
if length(paths) then
<span style="color: #004080;">sequence</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
res = split(paths[1],sep)[1..-2]
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">paths</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
for i=2 to length(paths) do
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">split</span><span style="color: #0000FF;">(</span><span style="color: #000000;">paths</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">],</span><span style="color: #000000;">sep</span><span style="color: #0000FF;">)[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..-</span><span style="color: #000000;">2</span><span style="color: #0000FF;">]</span>
sequence pi = split(paths[i],sep)[1..-2]
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">2</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">paths</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
for j=1 to length(res) do
<span style="color: #004080;">sequence</span> <span style="color: #000000;">pi</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">split</span><span style="color: #0000FF;">(</span><span style="color: #000000;">paths</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span><span style="color: #000000;">sep</span><span style="color: #0000FF;">)[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..-</span><span style="color: #000000;">2</span><span style="color: #0000FF;">]</span>
if j>length(pi) or res[j]!=pi[j] then
<span style="color: #008080;">for</span> <span style="color: #000000;">j</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">res</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
res = res[1..j-1]
<span style="color: #008080;">if</span> <span style="color: #000000;">j</span><span style="color: #0000FF;">></span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">pi</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">or</span> <span style="color: #000000;">res</span><span style="color: #0000FF;">[</span><span style="color: #000000;">j</span><span style="color: #0000FF;">]!=</span><span style="color: #000000;">pi</span><span style="color: #0000FF;">[</span><span style="color: #000000;">j</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">then</span>
exit
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">res</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">j</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span>
end if
<span style="color: #008080;">exit</span>
end for
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
if length(res)=0 then exit end if
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
end for
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">res</span><span style="color: #0000FF;">)=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
end if
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
return join(res,sep)
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
end function
<span style="color: #008080;">return</span> <span style="color: #7060A8;">join</span><span style="color: #0000FF;">(</span><span style="color: #000000;">res</span><span style="color: #0000FF;">,</span><span style="color: #000000;">sep</span><span style="color: #0000FF;">)</span>
 
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
constant test = {"/home/user1/tmp/coverage/test",
"/home/user1/tmp/covert/operator",
<span style="color: #008080;">constant</span> <span style="color: #000000;">test</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #008000;">"/home/user1/tmp/coverage/test"</span><span style="color: #0000FF;">,</span>
"/home/user1/tmp/coven/members"}
<span style="color: #008000;">"/home/user1/tmp/covert/operator"</span><span style="color: #0000FF;">,</span>
?common_directory_path(test)</lang>
<span style="color: #008000;">"/home/user1/tmp/coven/members"</span><span style="color: #0000FF;">}</span>
<span style="color: #0000FF;">?</span><span style="color: #000000;">common_directory_path</span><span style="color: #0000FF;">(</span><span style="color: #000000;">test</span><span style="color: #0000FF;">)</span>
<!--</syntaxhighlight>-->
{{out}}
<pre>
Line 1,724 ⟶ 1,984:
 
=={{header|PHP}}==
<langsyntaxhighlight lang="php"><?php
 
/*
Line 1,780 ⟶ 2,040:
}
 
?></langsyntaxhighlight>
 
 
<langsyntaxhighlight lang="php"><?php
 
/* A more compact string-only version, which I assume would be much faster */
Line 1,804 ⟶ 2,064:
}
 
?></langsyntaxhighlight>
 
=={{header|Picat}}==
Here are two different approaches. Both use <code>append/3</code> for getting the common prefix.
 
===Using maxof/2===
Using <code>maxof/2</code> to get the longest common prefix.
<syntaxhighlight lang="picat">find_common_directory_path(Dirs) = Path =>
maxof( (common_prefix(Dirs, Path,Len), append(_,"/",Path)), Len).
 
%
% Find a common prefix of all lists/strings in Ls.
% Using append/3.
%
common_prefix(Ls, Prefix,Len) =>
foreach(L in Ls)
append(Prefix,_,L)
end,
Len = Prefix.length.</syntaxhighlight>
 
===Mode-directed tabling===
Using mode-directed tabling for maximizing the length.
<syntaxhighlight lang="picat">find_common_directory_path2(Dirs) = Path =>
common_prefix2(Dirs,Path,'/',_Len).
 
table(+,-,max)
common_prefix2(Ls,Prefix,Len) =>
common_prefix2(Ls,Prefix,[],Len).
 
table(+,-,+,max)
common_prefix2(Ls,Prefix,Last,Len) =>
foreach(L in Ls)
append(Prefix,_,L)
end,
if Last != [], Prefix != [] then
Prefix.last() == Last
end,
Len = Prefix.length.</syntaxhighlight>
 
For the directories
<pre>
Dirs = [
"/home/user1/tmp/coverage/test",
"/home/user1/tmp/covert/operator",
"/home/user1/tmp/coven/members"
]
</pre>
 
both find this solution:
<pre>path = /home/user1/tmp/</pre>
 
=={{header|PicoLisp}}==
<langsyntaxhighlight PicoLisplang="picolisp">(de commonPath (Lst Chr)
(glue Chr
(make
(apply find
(mapcar '((L) (split (chop L) Chr)) Lst)
'(@ (or (pass <>) (nil (link (next))))) ) ) ) )</langsyntaxhighlight>
Output:
<pre>(commonPath
Line 1,822 ⟶ 2,131:
 
-> "/home/user1/tmp"</pre>
 
=={{header|Pike}}==
<langsyntaxhighlight Pikelang="pike">array paths = ({ "/home/user1/tmp/coverage/test",
"/home/user1/tmp/covert/operator",
"/home/user1/tmp/coven/members" });
Line 1,833 ⟶ 2,143:
string cp = String.common_prefix(paths);
cp = cp[..sizeof(cp)-search(reverse(cp), "/")-2];
Result: "/home/user1/tmp"</langsyntaxhighlight>
 
=={{header|PowerBASIC}}==
{{Trans|Visual Basic}}
<langsyntaxhighlight lang="powerbasic">#COMPILE EXE
#DIM ALL
#COMPILER PBCC 6
Line 1,904 ⟶ 2,214:
CON.WAITKEY$
 
END FUNCTION</langsyntaxhighlight>
{{out}}
<pre>/home/user1/tmp/coverage/test
Line 1,924 ⟶ 2,234:
=={{header|PowerShell}}==
 
<syntaxhighlight lang="powershell">
<lang Powershell>
<#
.Synopsis
Line 1,952 ⟶ 2,262:
}
}
</syntaxhighlight>
</lang>
 
Sample execution:
<syntaxhighlight lang="text">
"C:\a\b\c\d\e","C:\a\b\e\f","C:\a\b\c\d\x" | Get-CommonPath
C:\a\b
</syntaxhighlight>
</lang>
 
=={{header|Prolog}}==
 
<syntaxhighlight lang="prolog">
 
%! directory_prefix(PATHs,STOP0,PREFIX)
 
directory_prefix([],_STOP0_,'')
:-
!
.
 
directory_prefix(PATHs0,STOP0,PREFIX)
:-
prolog:once(longest_prefix(PATHs0,STOP0,LONGEST_PREFIX)) ->
prolog:atom_concat(PREFIX,STOP0,LONGEST_PREFIX) ;
PREFIX=''
.
 
%! longest_prefix(PATHs,STOP0,PREFIX)
 
longest_prefix(PATHs0,STOP0,PREFIX)
:-
QUERY=(shortest_prefix(PATHs0,STOP0,SHORTEST_PREFIX)) ,
prolog:findall(SHORTEST_PREFIX,QUERY,SHORTEST_PREFIXs) ,
lists:reverse(SHORTEST_PREFIXs,LONGEST_PREFIXs) ,
lists:member(PREFIX,LONGEST_PREFIXs)
.
 
%! shortest_prefix(PATHs,STOP0,PREFIX)
 
shortest_prefix([],_STOP0_,_PREFIX_) .
 
shortest_prefix([PATH0|PATHs0],STOP0,PREFIX)
:-
starts_with(PATH0,PREFIX) ,
ends_with(PREFIX,STOP0) ,
shortest_prefix(PATHs0,STOP0,PREFIX)
.
 
%! starts_with(TARGET,START)
 
starts_with(TARGET,START)
:-
prolog:atom_concat(START,_,TARGET)
.
 
%! ends_with(TARGET,END)
 
ends_with(TARGET,END)
:-
prolog:atom_concat(_,END,TARGET)
.
 
</syntaxhighlight>
 
{{out}}
<pre>
?- directory_prefix(['/home/user1/tmp/coverage/test','/home/user1/tmp/convert/operator','/home/user1/tmp/coven/members'],'/',PREFIX) .
PREFIX = '/home/user1/tmp' .
</pre>
 
=={{header|PureBasic}}==
Line 1,965 ⟶ 2,336:
 
Simply by checking the catalog names until they mismatch and add up the correct parts, the task is accomplished.
<langsyntaxhighlight PureBasiclang="purebasic">Procedure.s CommonPath(Array InPaths.s(1),separator.s="/")
Protected SOut$=""
Protected i, j, toggle
Line 1,987 ⟶ 2,358:
Next
ForEver
EndProcedure</langsyntaxhighlight>
 
Example of implementation
<langsyntaxhighlight PureBasiclang="purebasic">Dim t.s(2)
t(0)="/home/user1/tmp/coverage/test"
t(1)="/home/user1/tmp/covert/operator"
t(2)="/home/user1/tmp/coven/members"
 
Debug CommonPath(t(),"/"))</langsyntaxhighlight>
 
=={{header|Python}}==
 
Since Python 3.5 os.path.commonpath function can be used:
<syntaxhighlight lang="python">>>> import os
>>> os.path.commonpath(['/home/user1/tmp/coverage/test',
'/home/user1/tmp/covert/operator', '/home/user1/tmp/coven/members'])
'/home/user1/tmp'</syntaxhighlight>
 
The Python os.path.commonprefix function is [http://nedbatchelder.com/blog/201003/whats_the_point_of_ospathcommonprefix.html broken] as it returns common characters that may not form a valid directory path:
<langsyntaxhighlight lang="python">>>> import os
>>> os.path.commonprefix(['/home/user1/tmp/coverage/test',
'/home/user1/tmp/covert/operator', '/home/user1/tmp/coven/members'])
'/home/user1/tmp/cove'</langsyntaxhighlight>
 
This result can be fixed:
<langsyntaxhighlight lang="python">>>> def commonprefix(args, sep='/'):
return os.path.commonprefix(args).rpartition(sep)[0]
 
>>> commonprefix(['/home/user1/tmp/coverage/test',
'/home/user1/tmp/covert/operator', '/home/user1/tmp/coven/members'])
'/home/user1/tmp'</langsyntaxhighlight>
 
Even shorter:
<langsyntaxhighlight lang="python">>>> paths = ['/home/user1/tmp/coverage/test', '/home/user1/tmp/covert/operator', '/home/user1/tmp/coven/members']
>>> os.path.dirname(os.path.commonprefix(paths))
'/home/user1/tmp'</langsyntaxhighlight>
 
But it may be better to not rely on the faulty implementation at all:
<langsyntaxhighlight lang="python">>>> from itertools import takewhile
>>> def allnamesequal(name):
return all(n==name[0] for n in name[1:])
Line 2,033 ⟶ 2,411:
'/home/user1/tmp/covert/operator', '/home/user1/tmp/coven/members'])
'/home/user1/tmp'
>>> </langsyntaxhighlight>
 
=={{header|Quackery}}==
 
<syntaxhighlight lang="Quackery"> [ over size
over size min
dup dip unrot times
[ over i^ peek
over i^ peek
!= if
[ rot drop
i^ unrot
conclude ] ]
2drop ] is equalto ( $ $ --> n )
 
[ 0 unrot over size
times
[ over i peek
over = if
[ rot drop
i unrot
conclude ] ]
2drop ] is lastof ( $ c --> n )
 
[ swap behead swap
witheach
[ over equalto
split drop ]
dup rot lastof
split drop ] is cdp ( [ c --> n )
 
$ '/home/user1/tmp/coverage/test
/home/user1/tmp/covert/operator
/home/user1/tmp/coven/members' nest$
char / cdp echo$</syntaxhighlight>
 
{{out}}
 
<pre>/home/user1/tmp</pre>
 
=={{header|R}}==
<syntaxhighlight lang="r">
<lang r>
get_common_dir <- function(paths, delim = "/")
{
Line 2,059 ⟶ 2,475:
get_common_dir(paths) # "/home/user1/tmp"
 
</syntaxhighlight>
</lang>
 
=={{header|Racket}}==
<syntaxhighlight lang="racket">
<lang Racket>
#lang racket
 
Line 2,081 ⟶ 2,497:
"/home/user1/tmp/coven/members")
;; --> "/home/user1/tmp"
</syntaxhighlight>
</lang>
 
=={{header|Raku}}==
(formerly Perl 6)
<syntaxhighlight lang="raku" line>my $sep = '/';
my @dirs = </home/user1/tmp/coverage/test
/home/user1/tmp/covert/operator
/home/user1/tmp/coven/members>;
 
my @comps = @dirs.map: { [ .comb(/ $sep [ <!before $sep> . ]* /) ] };
 
my $prefix = '';
 
while all(@comps[*]»[0]) eq @comps[0][0] {
$prefix ~= @comps[0][0] // last;
@comps».shift;
}
 
say "The longest common path is $prefix";
</syntaxhighlight>
Output:
<pre>
The longest common path is /home/user1/tmp
</pre>
If you'd prefer a pure FP solution without side effects, you can use this:
<syntaxhighlight lang="raku" line>my $sep := '/';
my @dirs := </home/user1/tmp/coverage/test
/home/user1/tmp/covert/operator
/home/user1/tmp/coven/members>;
 
my @comps = @dirs.map: { [ .comb(/ $sep [ <!before $sep> . ]* /) ] };
 
say "The longest common path is ",
gather for 0..* -> $column {
last unless all(@comps[*]»[$column]) eq @comps[0][$column];
take @comps[0][$column] // last;
}</syntaxhighlight>
Or here's another factoring, that focuses on building the result with cumulative sequences and getting the solution with `first`:
<syntaxhighlight lang="raku" line>my $sep = '/';
my @dirs = </home/user1/tmp/coverage/test
/home/user1/tmp/covert/operator
/home/user1/tmp/coven/members>;
 
sub is_common_prefix { so $^prefix eq all(@dirs).substr(0, $prefix.chars) }
 
say ([\~] @dirs.comb(/ $sep [ <!before $sep> . ]* /)).reverse.first: &is_common_prefix</syntaxhighlight>
 
=={{header|REXX}}==
<langsyntaxhighlight lang="rexx">/*REXX program finds the common directory path for a list of files. */
/* original code: Gerard Schildberger @. = /*the default for all file lists (null)*/
/* 20230606 Walter Pachl refurbisher adn improved (file.4 = 'home' -> /) */
@.1 = '/home/user1/tmp/coverage/test'
file. = '' /*the default for all file lists (null)*/
@.2 = '/home/user1/tmp/covert/operator'
@file.31 = '/home/user1/tmp/covencoverage/memberstest'
/*123456789.123456789.123456768*/
L= length(@.1) /*use the length of the first string. */
file.2 = '/home/user1/tmp/covert/operator'
do j=2 while @.j\=='' /*start search with the second string. */
file.3 = '/home/user1/tmp/coven/members'
_= compare(@.j, @.1) /*use REXX compare BIF for comparison*/
if _==0 then iterate /*Strings are equal? Then con't use min*/
L= min(L, _) /*get the minimum length equal strings.*/
if right(@.j, 1)=='/' then iterate /*if a directory, then it's OK. */
L= lastpos('/', left(@.j, L) ) /*obtain directory name up to here*/
end /*j*/
 
commonL= leftlength( @file.1,) lastpos('/', @.1, L) ) /*determineuse the shortestlength of DIRthe first string. */
Do j=2 While file.j\=='' /*loop for the other file names */
if right(common, 1)=='/' then common= left(common, max(0, length(common) - 1) )
diffp=compare(file.j,file.1) /*find the first different character */
if common=='' then common= "/" /*if no common directory, assume home. */
say 'common directoryIf diffp>0 Then Do path: ' common /*Strings are different [↑] handle trailing / delimiter*/
L=min(L,diffp) /*stickget athe forkminimum inlength it,equal we're all donestrings. */</lang>
If right(file.j,1)<>'/' Then Do /*not a directory */
L=lastpos('/',left(file.j,L)) /* go back to directory end */
If L=0 Then Do
Say 'common directory path: /'
Exit
End
End
End
End
common=left(file.1,lastpos('/',file.1,L)) /*determine the shortest DIR string.*/
If right(common,1)=='/' Then /* remove the trailing / */
common=left(common,length(common)-1)
If common=='' then common= "/" /*if no common directory, assume home. */
Say 'common directory path: 'common
/*stick a fork in it, we're all done. */
</syntaxhighlight>
{{out|output|text=&nbsp; when using the default inputs:}}
<pre>
Line 2,109 ⟶ 2,581:
 
=={{header|Ring}}==
<langsyntaxhighlight lang="ring">
# Project : Find common directory path
 
Line 2,134 ⟶ 2,606:
end
return left(p[1], o-1)
</syntaxhighlight>
</lang>
Output:
<pre>
/home/user1/tmp
</pre>
 
=={{header|RPL}}==
{{works with|HP|48}}
≪ DUP SIZE → paths n
≪ paths n GET "/" +
'''WHILE''' 'n' DECR '''REPEAT'''
paths n GET "/" +
DUP2 SIZE SWAP SIZE MIN DUP
1 SWAP '''FOR''' j
DROP
OVER j DUP SUB OVER j DUP SUB ≠
j
'''IF''' SWAP '''THEN''' DUP 1 ≠ - OVER SIZE 'j' STO '''END'''
'''NEXT'''
1 SWAP SUB SWAP DROP
'''END'''
DUP SIZE
'''WHILE''' DUP2 DUP SUB "/" ≠ '''REPEAT''' 1 - '''END'''
DUP 1 ≠ -
1 SWAP SUB
≫ ≫ '<span style="color:blue">CPATH</span>' STO
 
{ "/home/user1/tmp/coverage/test" "/home/user1/tmp/covert/operator" "/home/user1/tmp/coven/members" } <span style="color:blue">CPATH</span>
{{out}}
<pre>
1: "/home/user1/tmp"
</pre>
 
Line 2,143 ⟶ 2,642:
Uses the standard library <code>[http://www.ruby-doc.org/stdlib/libdoc/abbrev/rdoc/index.html abbrev]</code> module: Given a set of strings, calculate the set of unambiguous abbreviations for those strings, and return a hash where the keys are all the possible abbreviations and the values are the full strings.
 
<langsyntaxhighlight lang="ruby">require 'abbrev'
 
dirs = %w( /home/user1/tmp/coverage/test /home/user1/tmp/covert/operator /home/user1/tmp/coven/members )
 
common_prefix = dirs.abbrev.keys.min_by {|key| key.length}.chop # => "/home/user1/tmp/cove"
common_directory = common_prefix.sub(%r{/[^/]*$}, '') # => "/home/user1/tmp"</langsyntaxhighlight>
 
Implementing without that module:
<langsyntaxhighlight lang="ruby">separator = '/'
path0, *paths = dirs.collect {|dir| dir.split(separator)}
uncommon_idx = path0.zip(*paths).index {|dirnames| dirnames.uniq.length > 1}
uncommon_idx = path0.length unless uncommon_idx # if uncommon_idx==nil
common_directory = path0[0...uncommon_idx].join(separator) # => "/home/user1/tmp"</langsyntaxhighlight>
 
or method version
<langsyntaxhighlight lang="ruby">def common_directory_path(dirs, separator='/')
dir1, dir2 = dirs.minmax.map{|dir| dir.split(separator)}
dir1.zip(dir2).take_while{|dn1,dn2| dn1==dn2}.map(&:first).join(separator)
end
 
p common_directory_path(dirs) #=> "/home/user1/tmp"</langsyntaxhighlight>
 
=={{header|Run BASIC}}==
<langsyntaxhighlight lang="runbasic">' ------------------------------------------
' Find common directory to all directories
' and directories common with other Paths
Line 2,251 ⟶ 2,750:
html "</TABLE>"
wait
end</langsyntaxhighlight>
========= Common paths ================<br />
shows only the first few common paths..
Line 2,288 ⟶ 2,787:
</TR><TR><TD>11</TD><TD>/home/user1/tmp3/covert/operator</TD><TD>/home/user1/tmp3/</TD><TD>12</TD><TD>/home/user1/tmp3/coven/members</TD>
<TR></TABLE>
 
 
=={{header|Rust}}==
Rust has specific types for owned and borrowed paths. PathBuf is an 'owned' pointer to a path, Path is a borrow; this is similar to String and str, respectively.
 
<syntaxhighlight lang="rust">
<lang Rust>
use std::path::{Path, PathBuf};
 
Line 2,344 ⟶ 2,842:
}
}
</syntaxhighlight>
</lang>
 
=={{header|Scala}}==
===Naive===
This simple solution solves the task as given, but has oddities for edge cases due to the implementation of java.lang.String#split.
<langsyntaxhighlight Scalalang="scala">object FindCommonDirectoryPath extends App {
def commonPath(paths: List[String]): String = {
def common(a: List[String], b: List[String]): List[String] = (a, b) match {
Line 2,365 ⟶ 2,863:
)
println(commonPath(test))
}</langsyntaxhighlight>
Output:
<pre>/home/user1/tmp</pre>
===Advanced===
This implementation will handle various edge cases and relative paths. It also includes any common trailing '/' but callers can remove this if desired.
<langsyntaxhighlight Scalalang="scala">object FindCommonDirectoryPathRelative extends App {
def commonPath(paths: List[String]): String = {
val SEP = "/"
Line 2,419 ⟶ 2,917:
assert(commonPath(List("/a/a/", "/a/b/")) == "/a/")
assert(commonPath(List("/a/b/", "/a/b/")) == "/a/b/")
}</langsyntaxhighlight>
 
=={{header|Seed7}}==
Line 2,429 ⟶ 2,927:
but they need to make sure that a path does not end with a slash.
 
<langsyntaxhighlight lang="seed7">$ include "seed7_05.s7i";
 
const func integer: commonLen (in array string: names, in char: sep) is func
Line 2,470 ⟶ 2,968:
writeln("Common path: " <& names[1][.. length]);
end if;
end func;</langsyntaxhighlight>
 
Output:
Line 2,478 ⟶ 2,976:
 
=={{header|Sidef}}==
<langsyntaxhighlight lang="ruby">var dirs = %w(
/home/user1/tmp/coverage/test
/home/user1/tmp/covert/operator
Line 2,486 ⟶ 2,984:
var unique_pref = dirs.map{.split('/')}.abbrev.min_by{.len};
var common_dir = [unique_pref, unique_pref.pop][0].join('/');
say common_dir; # => /home/user1/tmp</langsyntaxhighlight>
 
=={{header|Standard ML}}==
<syntaxhighlight lang="sml">fun takeWhileEq ([], _) = []
| takeWhileEq (_, []) = []
| takeWhileEq (x :: xs, y :: ys) =
if x = y then x :: takeWhileEq (xs, ys) else []
 
fun commonPath sep =
let
val commonInit = fn [] => [] | x :: xs => foldl takeWhileEq x xs
and split = String.fields (fn c => c = sep)
and join = String.concatWith (str sep)
in
join o commonInit o map split
end
 
val paths = [
"/home/user1/tmp/coverage/test",
"/home/user1/tmp/covert/operator",
"/home/user1/tmp/coven/members"
]
 
val () = print (commonPath #"/" paths ^ "\n")</syntaxhighlight>
 
=={{header|Swift}}==
Line 2,492 ⟶ 3,013:
The below solution works only in swift in Linux.
 
<langsyntaxhighlight lang="swift">import Foundation
 
 
Line 2,508 ⟶ 3,029:
 
var output:String = getPrefix(test)!
print(output)</langsyntaxhighlight>
 
===Works on MacOS===
<syntaxhighlight lang="swift">
import Foundation
 
func commonPrefix<T: Equatable>(_ lhs: [T], _ rhs: [T]) -> [T] {
for tryLen in (0...min(lhs.count,rhs.count)).reversed() {
if lhs.starts(with: rhs.prefix(tryLen)) {
return Array<T>(rhs.prefix(tryLen))
}
}
return []
}
 
var test = ["/home/user1/tmp/coverage/test",
"/home/user1/tmp/covert/operator",
"/home/user1/tmp/coven/members"]
 
let lcp: String = test.reduce("") { lhs, rhs in
if !lhs.isEmpty {
var commonSoFar = commonPrefix(
lhs.components(separatedBy: "/"),
rhs.components(separatedBy: "/")
)
return commonSoFar.joined(separator: "/")
}
return rhs
}
print("Longest common path: \(lcp)")
 
// Longest common path: /home/user1/tmp
</syntaxhighlight>
 
=={{header|Tcl}}==
<langsyntaxhighlight lang="tcl">package require Tcl 8.5
proc pop {varname} {
upvar 1 $varname var
Line 2,529 ⟶ 3,082:
}
return [join $parts $separator]
}</langsyntaxhighlight>
 
<pre>% common_prefix {/home/user1/tmp/coverage/test /home/user1/tmp/covert/operator /home/user1/tmp/coven/members}
Line 2,535 ⟶ 3,088:
 
=={{header|TUSCRIPT}}==
<langsyntaxhighlight lang="tuscript">
$$ MODE TUSCRIPT
common=""
Line 2,550 ⟶ 3,103:
ENDIF
ENDLOOP
</syntaxhighlight>
</lang>
Output:
<pre>
Line 2,558 ⟶ 3,111:
=={{header|UNIX Shell}}==
The following is a pure Bourne Shell solution. The while loop controls the maximum depth to check paths.
<langsyntaxhighlight lang="bash">
#!/bin/sh
 
Line 2,579 ⟶ 3,132:
i=`expr $i + 1`
done
</syntaxhighlight>
</lang>
 
 
=={{header|Ursala}}==
The algorithm is to lex the paths into component directory names, and then find the greatest common prefix of those.
<langsyntaxhighlight Ursalalang="ursala">#import std
 
comdir"s" "p" = mat"s" reduce(gcp,0) (map sep "s") "p"</langsyntaxhighlight>
where <code>"s"</code> is a dummy variable representing the separator, <code>"p"</code> is a dummy variable representing the list of paths, and
*<code>sep</code> is second order function in the standard library that takes a separator character and returns a lexer mapping a string containing the separator to a list of the substrings found between occurrences of it
Line 2,594 ⟶ 3,146:
*<code>mat</code> is a second order function in the standard library that takes a separator character and returns a function that flattens a list of strings into a single string with copies of the separator inserted between them
Here is a version using operators instead of mnemonics for <code>map</code> and <code>reduce</code>.
<langsyntaxhighlight Ursalalang="ursala">comdir"s" "p" = mat"s" gcp:-0 sep"s"* "p"</langsyntaxhighlight>
Here is one in partly point-free form, using the composition operator (<code>+</code>).
<langsyntaxhighlight Ursalalang="ursala">comdir"s" = mat"s"+ gcp:-0+ sep"s"*</langsyntaxhighlight>
Here it is in point-free form.
<langsyntaxhighlight Ursalalang="ursala">comdir = +^/mat gcp:-0++ *+ sep</langsyntaxhighlight>
test program:
<langsyntaxhighlight Ursalalang="ursala">#cast %s
 
test =
Line 2,607 ⟶ 3,159:
'/home/user1/tmp/coverage/test',
'/home/user1/tmp/covert/operator',
'/home/user1/tmp/coven/members'></langsyntaxhighlight>
output:
<pre>'/home/user1/tmp'</pre>
Line 2,615 ⟶ 3,167:
=={{header|VBScript}}==
{{works with|Windows Script Host|*}}
<syntaxhighlight lang="vbscript">
<lang VBScript>
' Read the list of paths (newline-separated) into an array...
strPaths = Split(WScript.StdIn.ReadAll, vbCrLf)
Line 2,647 ⟶ 3,199:
' Remove the final "/"...
WScript.Echo Left(strPath, Len(strPath) - 1)
</syntaxhighlight>
</lang>
 
=={{header|Visual Basic}}==
Line 2,654 ⟶ 3,206:
{{works with|VBA|6.5}}
{{works with|VBA|7.1}}
<langsyntaxhighlight lang="vb">Public Function CommonDirectoryPath(ParamArray Paths()) As String
Dim v As Variant
Dim Path() As String, s As String
Line 2,713 ⟶ 3,265:
"/"
 
End Sub</langsyntaxhighlight>
 
=={{header|Wren}}==
<syntaxhighlight lang="wren">var findCommonDir = Fn.new { |paths, sep|
var count = paths.count
if (count == 0) return ""
if (count == 1) return paths[0]
var splits = List.filled(count, null)
for (i in 0...count) splits[i] = paths[i].split(sep)
var minLen = splits[0].count
for (i in 1...count) {
var c = splits[i].count
if (c < minLen) minLen = c
}
if (minLen < 2) return ""
var common = ""
for (i in 1...minLen) {
var dir = splits[0][i]
for (j in 1...count) {
if (splits[j][i] != dir) return common
}
common = common + sep + dir
}
return common
}
 
var paths = [
"/home/user1/tmp/coverage/test",
"/home/user1/tmp/covert/operator",
"/home/user1/tmp/coven/members"
]
System.write("The common directory path is: ")
System.print(findCommonDir.call(paths, "/"))</syntaxhighlight>
 
{{out}}
<pre>
The common directory path is: /home/user1/tmp
</pre>
 
=={{header|Yabasic}}==
{{trans|GW-BASIC}}
<syntaxhighlight lang="yabasic">x$ = "/home/user1/tmp/coverage/test"
y$ = "/home/user1/tmp/covert/operator"
z$ = "/home/user1/tmp/coven/members"
 
a = len(x$)
if a > len(y$) a = len(y$)
if a > len(z$) a = len(z$)
for i = 1 to a
if mid$(x$, i, 1) <> mid$(y$, i, 1) break
next i
a = i - 1
 
for i = 1 to a
if mid$(x$, i, 1) <> mid$(z$, i, 1) break
next i
a = i - 1
 
if mid$(x$, i, 1) <> "/" then
for i = a to 1 step -1
if "/" = mid$(x$, i, 1) break
next i
fi
 
REM Task description says no trailing slash, so...
a = i - 1
print "Common path is '", left$(x$, a), "'"</syntaxhighlight>
 
=={{header|zkl}}==
<langsyntaxhighlight lang="zkl">dirs:=T("/home/user1/tmp/coverage/test", "/home/user1/tmp/covert/operator",
"/home/user1/tmp/coven/members");
n:=Utils.zipWith('==,dirs.xplode()).find(False); // character pos which differs
n=dirs[0][0,n].rfind("/"); // find last "/"
dirs[0][0,n];</langsyntaxhighlight>
{{out}}
<pre>
45

edits