Find common directory path: Difference between revisions
no edit summary
(→{{header|Python}}: os.path.commonpath for Pythons 3.5+) |
No edit summary |
||
(27 intermediate revisions by 16 users not shown) | |||
Line 17:
{{trans|C}}
<
V pos = 0
L
Line 34:
‘/home/user1/tmp/coverage/test’,
‘/home/user1/tmp/covert/operator’,
‘/home/user1/tmp/coven/members’]))</
{{out}}
Line 42:
=={{header|Ada}}==
<
with Ada.Text_IO; use Ada.Text_IO;
Line 80:
);
end Test_Common_Path;
</syntaxhighlight>
Output:
<pre>
Line 87:
=={{header|Aime}}==
<
{
integer e;
Line 111:
0;
}</
=={{header|ALGOL 68}}==
Line 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]}}
<
CHAR dir sep = "/"; # Assume POSIX #
Line 177:
);
print((dir name(common prefix(dir list)), new line))
)</
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}}==
<
Dir2 := "/home/user1/tmp/covert/operator"
Dir3 := "/home/user1/tmp/coven/members"
Line 198 ⟶ 264:
Else Break
MsgBox, % Result</
Message box shows:
<pre>/home/user1/tmp</pre>
=={{header|AWK}}==
<
# paths[count], where sep is a single-character directory separator.
function common_dir(paths, count, sep, b, c, f, i, j, p) {
Line 243 ⟶ 309:
a[3] = "/home/user1/tmp/coven/members"
print common_dir(a, 3, "/")
}</
Prints <tt>/home/user1/tmp</tt>.
Line 255 ⟶ 321:
Also, under FreeBASIC, the <code>pathSep</code> arg to <code>commonPath$</code> could be made optional, or even system-dependent.
<
DATA "/home/user2", "/home/user1/tmp/covert/operator", "/home/user1/tmp/coven/members"
Line 306 ⟶ 372:
commonPath$ = tmpstr1
END IF
END FUNCTION</
=={{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}}==
<
@echo off
setlocal enabledelayedexpansion
Line 371 ⟶ 466:
endlocal
exit /b
</syntaxhighlight>
{{out}}
<pre>
Line 378 ⟶ 473:
=={{header|BBC BASIC}}==
<
path$(1) = "/home/user1/tmp/coverage/test"
Line 396 ⟶ 491:
NEXT J%
UNTIL I% = 0
= LEFT$(p$(1), O%-1)</
=={{header|C}}==
<
int common_len(const char *const *names, int n, char sep)
Line 432 ⟶ 527:
return 0;
}</
=={{header|C sharp|C#}}==
<
using System;
using System.Collections.Generic;
Line 500 ⟶ 595:
}
</syntaxhighlight>
=={{header|C++}}==
<
#include <iostream>
#include <string>
Line 533 ⟶ 628:
std::string::size_type found = compareString.rfind( separator , maxCharactersCommon ) ;
return compareString.substr( 0 , found ) ;
}</
Output:
<pre>
Line 540 ⟶ 635:
=={{header|Clojure}}==
<
(defn common-prefix [sep paths]
Line 553 ⟶ 648:
["/home/user1/tmp/coverage/test"
"/home/user1/tmp/covert/operator"
"/home/user1/tmp/coven/members"]))</
=={{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.
<
string commonDirPath(in string[] paths, in string sep = "/") pure {
Line 570 ⟶ 682:
"/home/user1/tmp/coven/members"];
writeln(`The common path is: "`, paths.commonDirPath, '"');
}</
{{out}}
<pre>The common path is: "/home/user1/tmp"</pre>
=={{header|Delphi}}==
{{libheader| System.SysUtils}}
<syntaxhighlight lang="delphi">
program Find_common_directory_path;
Line 635 ⟶ 747:
'/home/user1/tmp/coven/members']));
Readln;
end.</
{{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}}
<
def common_directory_path(dirs, separator \\ "/") do
dir1 = Enum.min(dirs) |> String.split(separator)
Line 651 ⟶ 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)</
{{out}}
Line 659 ⟶ 795:
=={{header|Erlang}}==
<syntaxhighlight lang="erlang">
-module( find_common_directory ).
Line 671 ⟶ 807:
keep_common( Components, Acc ) -> [X || X <- Components, Y <- Acc, X =:= Y].
</syntaxhighlight>
{{out}}
<pre>
Line 679 ⟶ 815:
=={{header|F_Sharp|F#}}==
<
let (|SeqNode|SeqEmpty|) s =
Line 708 ⟶ 844:
printfn "The common preffix is: %A" (String.Join("/", (commonPrefix args)))
0</
Output for the given task input
<pre>The common preffix is: "/home/user1/tmp"</pre>
=={{header|Factor}}==
<
[ shorter? ] 2keep ? ;
Line 723 ⟶ 859:
: common-prefix ( seq separator -- prefix )
[ ] swap '[ _ common-prefix-1 ] map-reduce ;</
( scratchpad ) {
Line 734 ⟶ 870:
=={{header|FreeBASIC}}==
{{Trans|Visual Basic}}
<
' compile: fbc.exe -s console cdp.bas
Line 799 ⟶ 935:
Print : Print "hit any key to end program"
Sleep
End</
{{out}}
<pre>/home/user1/tmp/coverage/test
Line 816 ⟶ 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}}==
<
Dim sFolder As String[] = ["/home/user1/tmp/coverage/test", "/home/user1/tmp/covert/operator", "/home/user1/tmp/coven/members"]
Dim sSame As String
Line 834 ⟶ 1,000:
Print Mid(sSame, 1, RInStr(sSame, "/") - 1)
End</
Output:
<pre>
Line 845 ⟶ 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>.
<
import (
Line 923 ⟶ 1,089:
fmt.Println("Common path:", c)
}
}</
=={{header|Groovy}}==
Solution:
<
def pathParts = paths.collect { it.split(delim) }
pathParts.transpose().inject([match:true, commonParts:[]]) { aggregator, part ->
Line 934 ⟶ 1,100:
aggregator
}.commonParts.join(delim)
}</
Test:
<
'/home/user1/tmp/coverage/test',
'/home/user1/tmp/covert/operator',
Line 946 ⟶ 1,112:
'/home/user1/tmp/covert/test',
'/home/user1/tmp/coven/test',
'/home/user1/tmp/covers/test')</
Output:
Line 955 ⟶ 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 960 ⟶ 1,127:
Note that if the root directory is the common path, this reports the same as no match found (i.e. blank result).
<
110 X$ = "/home/user1/tmp/coverage/test"
Line 988 ⟶ 1,155:
350 A = L0 - 1
360 P$ = LEFT$(X$, A)
370 PRINT "Common path is '"; P$; "'"</
Output:
Line 995 ⟶ 1,162:
=={{header|Haskell}}==
<
-- Return the common prefix of two lists.
Line 1,017 ⟶ 1,184:
"/home/user1/tmp/covert/operator",
"/home/user1/tmp/coven/members"
]</
Or, expressed directly in applicative terms:
<
import Data.List.Split (splitOn)
Line 1,040 ⟶ 1,207:
, "/home/user1/tmp/covert/operator"
, "/home/user1/tmp/coven/members"
]</
{{Out}}
<pre>/home/user1/tmp</pre>
=={{header|HicEst}}==
<
minLength = MIN( LEN(a), LEN(b), LEN(c) )
Line 1,058 ⟶ 1,225:
WRITE(Messagebox, Name) "No common directory for", a, b, c
ENDIF
ENDDO</
=={{header|Icon}} and {{header|Unicon}}==
<
write(lcdsubstr(["/home/user1/tmp/coverage/test","/home/user1/tmp/covert/operator","/home/user1/tmp/coven/members"]))
end
Line 1,080 ⟶ 1,247:
if not match(s,x) then fail
return s
end</
=={{header|J}}==
'''Solution:'''
<
getCommonPrefix =: {. ;@{.~ 0 i.~ *./@(="1 {.)
getCommonDirPath=: [: getCommonPrefix parseDirs&></
'''Example:'''
<
getCommonPrefix >paths
/home/user1/tmp/cove
'/' getCommonDirPath paths
/home/user1/tmp/</
'''Note:'''
This alternative formulation of parseDirs provides cross-platform support, without the need to specify the path separator.
<
=={{header|Java}}==
{{works with|Java|1.5+}}
This example is case-sensitive.
<
public static String commonPath(String... paths){
String commonPath = "";
Line 1,141 ⟶ 1,308:
System.out.println(commonPath(paths2));
}
}</
Output:
<pre>/home/user1/tmp/
Line 1,148 ⟶ 1,315:
A slightly modified version of the previous program, only the method commonPath() is changed.
<
static String commonPath(String... paths){
String commonPath = "";
Line 1,167 ⟶ 1,334:
return commonPath;
}
</syntaxhighlight>
=={{header|JavaScript}}==
<
/**
* Given an array of strings, return an array of arrays, containing the
Line 1,216 ⟶ 1,383:
console.log(`Common path is: ${commonPath(cdpInput)}`);
</syntaxhighlight>
{{out}}
Line 1,224 ⟶ 1,391:
=={{header|jq}}==
<
def maximal_initial_subarray:
(map( .[0] ) | unique) as $u
Line 1,237 ⟶ 1,404:
[.[] | split(slash)] | maximal_initial_subarray | join(slash) ;
common_path("/")</
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:
<
"home/user1/tmp"</
=={{header|Julia}}==
{{works with|Julia|0.6}}
<
0 < length(ds) || return ""
1 < length(ds) || return String(ds[1])
Line 1,265 ⟶ 1,432:
println("Comparing:\n - ", join(test, "\n - "))
println("for their common directory path yields:\n", commonpath(test))</
{{out}}
Line 1,276 ⟶ 1,443:
=={{header|Kotlin}}==
<
fun findCommonDirPath(paths: List<String>, separator: Char): String {
Line 1,303 ⟶ 1,470:
println("The common directory path of:\n\n$pathsToPrint\n")
println("is '${findCommonDirPath(paths, '/')}'")
}</
{{out}}
Line 1,317 ⟶ 1,484:
=={{header|Lasso}}==
<
local(
Line 1,333 ⟶ 1,500:
}
stdoutnl(commonpath(#path1, #path2, #path3))</
Output:
Line 1,339 ⟶ 1,506:
=={{header|Liberty BASIC}}==
<
path$(2) = "/home/user1/tmp/covert/operator"
path$(3) = "/home/user1/tmp/coven/members"
Line 1,363 ⟶ 1,530:
end if
wend
end function</
=={{header|Lingo}}==
<
_player.itemDelimiter = sep
Line 1,384 ⟶ 1,551:
end repeat
return pathes[1].item[1..commonCnt]
end</
<
pathes.add("/home/user1/tmp/coverage/test")
pathes.add("/home/user1/tmp/covert/operator")
Line 1,391 ⟶ 1,558:
put getCommonPath(pathes, "/")
-- "/home/user1/tmp"</
=={{header|MapBasic}}==
Line 1,397 ⟶ 1,564:
Derived from the [https://www.rosettacode.org/wiki/Find_common_directory_path#BASIC BASIC] example above
<
Declare Sub Main
Line 1,462 ⟶ 1,629:
PRINT "Common path is " + commonPath(x(), Sep)
End Sub</
=={{header|Maple}}==
<syntaxhighlight lang="maple">
dirpath:=proc(a,b,c)
local dirtemp,dirnew,x;
Line 1,475 ⟶ 1,642:
end use;
end proc;
</syntaxhighlight>
=={{header|Mathematica}}/{{header|Wolfram Language}}==
<
[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/"</
=={{header|MATLAB}} / {{header|Octave}}==
<syntaxhighlight lang="matlab">
function lcp = longest_common_dirpath(varargin)
ix = find(varargin{1}=='/');
Line 1,497 ⟶ 1,664:
longest_common_dirpath('/home/user1/tmp/coverage/test', '/home/user1/tmp/covert/operator', '/home/user1/tmp/coven/members')
</syntaxhighlight>
{{out}}
Line 1,505 ⟶ 1,672:
=={{header|Maxima}}==
<
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,515 ⟶ 1,682:
commonpath(["c:/files/banister.jpg", "c:/files/bank.xls", "c:/files/banana-recipes.txt"]);
"c:/files"</
=={{header|MUMPS}}==
<syntaxhighlight lang="mumps">FCD
NEW D,SEP,EQ,LONG,DONE,I,J,K,RETURN
SET D(1)="/home/user1/tmp/coverage/test"
Line 1,532 ⟶ 1,699:
WRITE !,"The longest common directory is: ",RETURN
KILL D,SEP,EQ,LONG,DONE,I,J,K,RETURN
QUIT</
Usage:<pre>
USER>D FCD^ROSETTA
Line 1,543 ⟶ 1,710:
=={{header|Nim}}==
<
proc commonprefix(paths: openarray[string], sep = "/"): string =
Line 1,555 ⟶ 1,722:
result = result[0 .. result.rfind(sep)]
echo commonprefix(@["/home/user1/tmp/coverage/test", "/home/user1/tmp/covert/operator", "/home/user1/tmp/coven/members"])</
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
| x :: xs -> List.fold_left common_prefix x xs
| _ -> []
let
List.map Str.(split_delim (regexp_string sep)) paths
|> common_prefix_all
|> String.concat sep
let
common_ancestor ~sep:"/" [
"/home/user1/tmp/coverage/test";
"/home/user1/tmp/covert/operator";
"/home/user1/tmp/coven/members";
] = "/home/user1/tmp"
end</syntaxhighlight>
=={{header|OpenEdge/Progress}}==
<
i_cdirs AS CHAR,
i_cseparator AS CHAR
Line 1,622 ⟶ 1,781:
RETURN cresult.
END FUNCTION.</
<
findCommonDir(
'/home/user1/tmp/coverage/test' + '~n' +
Line 1,631 ⟶ 1,790:
'/'
)
VIEW-AS ALERT-BOX</
Output
Line 1,645 ⟶ 1,804:
=={{header|Oz}}==
With a few helper functions, we can express the solution like this in Oz:
<
fun {CommonPrefix Sep Paths}
fun {GetParts P} {String.tokens P Sep} end
Line 1,676 ⟶ 1,835:
["/home/user1/tmp/coverage/test"
"/home/user1/tmp/covert/operator"
"/home/user1/tmp/coven/members"]}}</
=={{header|PARI/GP}}==
<
my(s="");
v=apply(t->Vec(t),v);
Line 1,690 ⟶ 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"])</
=={{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,696 ⟶ 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)'':
<
my $sep = shift;
my $paths = join "\0", map { $_.$sep } @_;
$paths =~ /^ ( [^\0]* ) $sep [^\0]* (?: \0 \1 $sep [^\0]* )* $/x;
return $1;
}</
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:
<
sub common_prefix {
Line 1,716 ⟶ 1,937:
return first { $prefixes{$_} == @paths } reverse sort keys %prefixes;
}</
'''Testing:'''
<
/home/user1/tmp/covert/operator
/home/user1/tmp/coven/members);
print common_prefix('/', @paths), "\n";</
{{out}}
Line 1,731 ⟶ 1,952:
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)-->
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<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>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<span style="color: #008080;">exit</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<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>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<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>
<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>
<span style="color: #008000;">"/home/user1/tmp/covert/operator"</span><span style="color: #0000FF;">,</span>
<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,760 ⟶ 1,984:
=={{header|PHP}}==
<
/*
Line 1,816 ⟶ 2,040:
}
?></
<
/* A more compact string-only version, which I assume would be much faster */
Line 1,840 ⟶ 2,064:
}
?></
=={{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}}==
<
(glue Chr
(make
(apply find
(mapcar '((L) (split (chop L) Chr)) Lst)
'(@ (or (pass <>) (nil (link (next))))) ) ) ) )</
Output:
<pre>(commonPath
Line 1,860 ⟶ 2,133:
=={{header|Pike}}==
<
"/home/user1/tmp/covert/operator",
"/home/user1/tmp/coven/members" });
Line 1,870 ⟶ 2,143:
string cp = String.common_prefix(paths);
cp = cp[..sizeof(cp)-search(reverse(cp), "/")-2];
Result: "/home/user1/tmp"</
=={{header|PowerBASIC}}==
{{Trans|Visual Basic}}
<
#DIM ALL
#COMPILER PBCC 6
Line 1,941 ⟶ 2,214:
CON.WAITKEY$
END FUNCTION</
{{out}}
<pre>/home/user1/tmp/coverage/test
Line 1,961 ⟶ 2,234:
=={{header|PowerShell}}==
<syntaxhighlight lang="powershell">
<#
.Synopsis
Line 1,989 ⟶ 2,262:
}
}
</syntaxhighlight>
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>
=={{header|Prolog}}==
<
%! directory_prefix(PATHs,STOP0,PREFIX)
Line 2,050 ⟶ 2,323:
.
</syntaxhighlight>
{{out}}
Line 2,063 ⟶ 2,336:
Simply by checking the catalog names until they mismatch and add up the correct parts, the task is accomplished.
<
Protected SOut$=""
Protected i, j, toggle
Line 2,085 ⟶ 2,358:
Next
ForEver
EndProcedure</
Example of implementation
<
t(0)="/home/user1/tmp/coverage/test"
t(1)="/home/user1/tmp/covert/operator"
t(2)="/home/user1/tmp/coven/members"
Debug CommonPath(t(),"/"))</
=={{header|Python}}==
Since Python 3.5 os.path.commonpath function can be used:
<
>>> os.path.commonpath(['/home/user1/tmp/coverage/test',
'/home/user1/tmp/covert/operator', '/home/user1/tmp/coven/members'])
'/home/user1/tmp'</
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:
<
>>> os.path.commonprefix(['/home/user1/tmp/coverage/test',
'/home/user1/tmp/covert/operator', '/home/user1/tmp/coven/members'])
'/home/user1/tmp/cove'</
This result can be fixed:
<
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'</
Even shorter:
<
>>> os.path.dirname(os.path.commonprefix(paths))
'/home/user1/tmp'</
But it may be better to not rely on the faulty implementation at all:
<
>>> def allnamesequal(name):
return all(n==name[0] for n in name[1:])
Line 2,138 ⟶ 2,411:
'/home/user1/tmp/covert/operator', '/home/user1/tmp/coven/members'])
'/home/user1/tmp'
>>> </
=={{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">
get_common_dir <- function(paths, delim = "/")
{
Line 2,164 ⟶ 2,475:
get_common_dir(paths) # "/home/user1/tmp"
</syntaxhighlight>
=={{header|Racket}}==
<syntaxhighlight lang="racket">
#lang racket
Line 2,186 ⟶ 2,497:
"/home/user1/tmp/coven/members")
;; --> "/home/user1/tmp"
</syntaxhighlight>
=={{header|Raku}}==
(formerly Perl 6)
<syntaxhighlight lang="raku"
my @dirs = </home/user1/tmp/coverage/test
/home/user1/tmp/covert/operator
Line 2,205 ⟶ 2,516:
say "The longest common path is $prefix";
</syntaxhighlight>
Output:
<pre>
Line 2,211 ⟶ 2,522:
</pre>
If you'd prefer a pure FP solution without side effects, you can use this:
<syntaxhighlight lang="raku"
my @dirs := </home/user1/tmp/coverage/test
/home/user1/tmp/covert/operator
Line 2,222 ⟶ 2,533:
last unless all(@comps[*]»[$column]) eq @comps[0][$column];
take @comps[0][$column] // last;
}</
Or here's another factoring, that focuses on building the result with cumulative sequences and getting the solution with `first`:
<syntaxhighlight lang="raku"
my @dirs = </home/user1/tmp/coverage/test
/home/user1/tmp/covert/operator
Line 2,231 ⟶ 2,542:
sub is_common_prefix { so $^prefix eq all(@dirs).substr(0, $prefix.chars) }
say ([\~] @dirs.comb(/ $sep [ <!before $sep> . ]* /)).reverse.first: &is_common_prefix</
=={{header|REXX}}==
<
/* original code: Gerard Schildberger
/* 20230606 Walter Pachl refurbisher adn improved (file.4 = 'home' -> /) */
file. = '' /*the default for all file lists (null)*/
/*123456789.123456789.123456768*/
file.2 = '/home/user1/tmp/covert/operator'
file.3 = '/home/user1/tmp/coven/members'
Do j=2 While file.j\=='' /*loop for the other file names */
diffp=compare(file.j,file.1) /*find the first different character */
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= when using the default inputs:}}
<pre>
Line 2,259 ⟶ 2,581:
=={{header|Ring}}==
<
# Project : Find common directory path
Line 2,284 ⟶ 2,606:
end
return left(p[1], o-1)
</syntaxhighlight>
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,293 ⟶ 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.
<
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"</
Implementing without that module:
<
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"</
or method version
<
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"</
=={{header|Run BASIC}}==
<
' Find common directory to all directories
' and directories common with other Paths
Line 2,401 ⟶ 2,750:
html "</TABLE>"
wait
end</
========= Common paths ================<br />
shows only the first few common paths..
Line 2,442 ⟶ 2,791:
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">
use std::path::{Path, PathBuf};
Line 2,493 ⟶ 2,842:
}
}
</syntaxhighlight>
=={{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.
<
def commonPath(paths: List[String]): String = {
def common(a: List[String], b: List[String]): List[String] = (a, b) match {
Line 2,514 ⟶ 2,863:
)
println(commonPath(test))
}</
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.
<
def commonPath(paths: List[String]): String = {
val SEP = "/"
Line 2,568 ⟶ 2,917:
assert(commonPath(List("/a/a/", "/a/b/")) == "/a/")
assert(commonPath(List("/a/b/", "/a/b/")) == "/a/b/")
}</
=={{header|Seed7}}==
Line 2,578 ⟶ 2,927:
but they need to make sure that a path does not end with a slash.
<
const func integer: commonLen (in array string: names, in char: sep) is func
Line 2,619 ⟶ 2,968:
writeln("Common path: " <& names[1][.. length]);
end if;
end func;</
Output:
Line 2,627 ⟶ 2,976:
=={{header|Sidef}}==
<
/home/user1/tmp/coverage/test
/home/user1/tmp/covert/operator
Line 2,635 ⟶ 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</
=={{header|Standard ML}}==
<
| takeWhileEq (_, []) = []
| takeWhileEq (x :: xs, y :: ys) =
Line 2,658 ⟶ 3,007:
]
val () = print (commonPath #"/" paths ^ "\n")</
=={{header|Swift}}==
Line 2,664 ⟶ 3,013:
The below solution works only in swift in Linux.
<
Line 2,680 ⟶ 3,029:
var output:String = getPrefix(test)!
print(output)</
===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}}==
<
proc pop {varname} {
upvar 1 $varname var
Line 2,701 ⟶ 3,082:
}
return [join $parts $separator]
}</
<pre>% common_prefix {/home/user1/tmp/coverage/test /home/user1/tmp/covert/operator /home/user1/tmp/coven/members}
Line 2,707 ⟶ 3,088:
=={{header|TUSCRIPT}}==
<
$$ MODE TUSCRIPT
common=""
Line 2,722 ⟶ 3,103:
ENDIF
ENDLOOP
</syntaxhighlight>
Output:
<pre>
Line 2,730 ⟶ 3,111:
=={{header|UNIX Shell}}==
The following is a pure Bourne Shell solution. The while loop controls the maximum depth to check paths.
<
#!/bin/sh
Line 2,751 ⟶ 3,132:
i=`expr $i + 1`
done
</syntaxhighlight>
=={{header|Ursala}}==
The algorithm is to lex the paths into component directory names, and then find the greatest common prefix of those.
<
comdir"s" "p" = mat"s" reduce(gcp,0) (map sep "s") "p"</
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,765 ⟶ 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>.
<
Here is one in partly point-free form, using the composition operator (<code>+</code>).
<
Here it is in point-free form.
<
test program:
<
test =
Line 2,778 ⟶ 3,159:
'/home/user1/tmp/coverage/test',
'/home/user1/tmp/covert/operator',
'/home/user1/tmp/coven/members'></
output:
<pre>'/home/user1/tmp'</pre>
Line 2,786 ⟶ 3,167:
=={{header|VBScript}}==
{{works with|Windows Script Host|*}}
<syntaxhighlight lang="vbscript">
' Read the list of paths (newline-separated) into an array...
strPaths = Split(WScript.StdIn.ReadAll, vbCrLf)
Line 2,818 ⟶ 3,199:
' Remove the final "/"...
WScript.Echo Left(strPath, Len(strPath) - 1)
</syntaxhighlight>
=={{header|Visual Basic}}==
Line 2,825 ⟶ 3,206:
{{works with|VBA|6.5}}
{{works with|VBA|7.1}}
<
Dim v As Variant
Dim Path() As String, s As String
Line 2,884 ⟶ 3,265:
"/"
End Sub</
=={{header|Wren}}==
<
var count = paths.count
if (count == 0) return ""
Line 2,916 ⟶ 3,297:
]
System.write("The common directory path is: ")
System.print(findCommonDir.call(paths, "/"))</
{{out}}
Line 2,922 ⟶ 3,303:
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}}==
<
"/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];</
{{out}}
<pre>
|