Vampire
03/05/2025, 4:47 PMYoussef Shoaib [MOD]
03/05/2025, 4:56 PMfiles.map { it.canonicalPath }.reduce(String::commonPrefixWith)
Should give you the directory or file that contains them all (I don't know how much I like this though tbh)
You can easily write a variant of this by making a File.commonDenominatorWith(File)
functionVampire
03/05/2025, 4:59 PMfiles
.map { it.canonicalFile.invariantSeparatorsPath }
.reduce(CharSequence::commonPrefixWith)
.let(::File)
ephemient
03/05/2025, 5:02 PM"/home/user1/foo"
, "/home/user2/bar"
have "/home/user"
as the common prefixVampire
03/05/2025, 5:05 PMfiles
.map { it.canonicalFile.invariantSeparatorsPath }
.reduce(CharSequence::commonPrefixWith)
.substringBeforeLast('/')
.let(::File)
Vampire
03/05/2025, 5:05 PMephemient
03/05/2025, 5:10 PMC:\
, D:\
, \\?\
on Windows) may end up with no common denominator. but if you can ignore that, that seems okVampire
03/05/2025, 5:11 PMephemient
03/05/2025, 5:11 PMVampire
03/05/2025, 5:16 PMtoComponents().segments
would give the segments, had that first as I was playing in the debugger evaluator and didn't see it is internal, but then I still missed how to get the common prefix for two lists.ephemient
03/05/2025, 5:28 PMfun <T> Iterable<T>.commonPrefix(other: Iterable<T>): List<T> {
val otherIterator = other.iterator()
return this.takeWhile { otherIterator.hasNext() && it == otherIterator.next() }
}
Youssef Shoaib [MOD]
03/05/2025, 5:31 PMfun <T> commonPrefixOfLists(list1: List<T>, list2: List<T>): List<T> = buildList {
list1.zip(list2).forEach { (e1, e2) ->
if (e1 == e2) add(e1)
else return@buildList
}
}
Can definitely be improved by defining some sort of forEachZipped
function. I'm quite fond of the early-return here to short circuit the prefix-findingephemient
03/05/2025, 5:33 PMzip
is kinda overkill since it builds its own list… there's been more than once when I wished it didn't, and was just an iterator, but oh wellephemient
03/05/2025, 5:34 PMlist1.zip(list2) { e1, e2 ->
would work the same and avoid the intermediate pairs, but still ends up with an extra listVampire
03/05/2025, 5:40 PM/a/b/c
and /a/d/c
as result /a/c
ephemient
03/05/2025, 5:42 PMfun <T> commonPrefixOfLists(list1: List<T>, list2: List<T>): List<T> = buildList {
list1.zip(list2) { (e1, e2) ->
if (e1 == e2) add(e1)
else return@buildList
}
}
would work the same as Youssef's code, without `Pair`s. but it still has an intermediate List
that isn't needed if you work with the `Iterator`s directlyVampire
03/05/2025, 5:43 PMephemient
03/05/2025, 5:44 PMzip
very much in general :pVampire
03/05/2025, 5:44 PMYoussef Shoaib [MOD]
03/05/2025, 5:51 PMfun <T> commonPrefixOfLists(list1: List<T>, list2: List<T>): List<T> {
var i = 0
while(i < list1.length) {
if (list1[i] != list2[i]) {
i++
break
}
i++
}
return list1.sublist(0, i)
}
ephemient
03/05/2025, 5:52 PMList&RandomAccess
though :)ephemient
03/05/2025, 5:53 PMLinkedList
aren't RandomAccess
, and Kotlin doesn't expose that)