// Abstract ------------------------------------------------------------------------------------------------------------------------------

This sample is a collection of knowledges manipulating lists. It is based on Werner Het's P-99: Ninety-Nine Prolog Problems

// Examples ------------------------------------------------------------------------------------------------------------------------------

?- #lst.head([a,b,c,d],:e)
-> ( a ) := 1.00 (0.001) 1
?- #lst.tail([a,b,c,d],:e)
-> ( d ) := 1.00 (0.002) 1
?- #lst.ptail([a,b,c,d],:e)
-> ( c ) := 1.00 (0.001) 1
?- #lst.item([a,b,c,d],1,:e)
-> ( a ) := 1.00 (0.001) 1
?- #lst.length([a,b,c,d],:l)
-> ( 4 ) := 1.00 (0.002) 1
?- #lst.flip([a,b,c,d],:l)
-> ( [d, c, b, a] ) := 1.00 (0.002) 1
?- #lst.is.palindrome([k,a,y,a,k])
-> ( ) := 1.00 (0.001) 1
?- #lst.is.palindrome([p,i,a,n,o])
-> ( ) := 0.00 (0.001) 1
?- #lst.flat([a,[b,c],d,[e,[f,g]]],:l)
-> ( [a, b, c, d, e, f, g] ) := 1.00 (0.019) 1
?- #lst.zip([a,b,b,c,d,d,d,e,f,f],:l)
-> ( [a, b, c, d, e, f] ) := 1.00 (0.010) 1
?- #lst.pack([a,b,b,c,d,d,d,e,f,f],:l)
-> ( [[a], [b, b], [c], [d, d, d], [e], [f, f]] ) := 1.00 (0.014) 1
?- #lst.encode([a,b,b,c,d,d,d,e,f,f],:l)
-> ( [[1, a], [2, b], [1, c], [3, d], [1, e], [2, f]] ) := 1.00 (0.013) 1
?- #lst.encode2([a,b,b,c,d,d,d,e,f,f],:l)
-> ( [a, [2, b], c, [3, d], e, [2, f]] ) := 1.00 (0.015) 1
?- #lst.decode([[1, a], [2, b], [1, c], [3, d], [1, e], [2, f]],:l)
-> ( [a, b, b, c, d, d, d, e, f, f] ) := 1.00 (0.016) 1
?- #lst.drop([a,b,c,d,e,f,g,h],3,:l)
-> ( [a, b, d, e, g, h] ) := 1.00 (0.006) 1
?- #lst.split([a,b,c,d,e,f,g,h],3,:l1,:l2)
-> ( [a, b, c] , [d, e, f, g, h] ) := 1.00 (0.002) 1
?- #lst.slice([a,b,c,d,e,f,g,h],2,4,:l)
-> ( [b, c, d] ) := 1.00 (0.002) 1
?- #lst.rotate([a,b,c,d,e,f,g,h],2,:l)
-> ( [c, d, e, f, g, h, a, b] ) := 1.00 (0.002) 1
?- #lst.rotate([a,b,c,d,e,f,g,h],-3,:l) -> ( [d, e, f, g, h, a, b, c] ) := 1.00 (0.003) 1
 
// Code ----------------------------------------------------------------------------------------------------------------------------------

// fetch the first element in the list
lst.head {

    ([],[])^       :- true;
    ([:e],:e)^     :- true;
    ([:h|_],:h);
}

// fetch the last element in the list
lst.tail {

    ([],[])^        :- true;
    ([:e],:e)^      :- true;
    ([:h|:r],:l)    :- #lst.tail(:r,:l);

}

// fetch the previous to last element in the list
lst.ptail {

    ([],[])^        :- true;
    ([:e,_],:e)^    :- true;
    ([:h|:r],:l)    :- #lst.ptail(:r,:l);

}

// fetch the nth element in the list (1 to nth)
lst.item {

    ([],_,[])^          :- true;
    ([:e],1,:e)^        :- true;
    ([:h|:r],1,:h)^     :- true;
    ([:h|:r],:n,:l)     :- sub(:n,1,:m), #lst.item(:r,:m,:l);
}

// get the number of elements in a list
lst.length {

    ([],0)^     :- true;
    ([_],1)^    :- true;
    ([_|:r],:d) :- #lst.length(:r,:c), add(:c,1,:d);

}

// inverse the contents of the list
lst.flip {

    ([],[])^        :- true;
    ([:e],[:e])^    :- true;
    ([:h|:r],:l)    :- #lst.flip(:r,:l2), lst.cat(:l2,:h,:l);

}

// test if a list is a palindrome (content is the same read forward & backward, e.g. kayak)
lst.is.palindrome {

    (:l) :- lst.flip(:l,:l);

}

// flatten a list
lst.flat {

    (:i,:i)       :- !is.list(:i)^;
    ([:e],[:e])   :- !is.list(:e)^;
    ([:e],:f)     :- is.list(:e)^, #lst.flat(:e,:f);
    ([:h|:r],:l)  :- #lst.flat(:h,:hf), #lst.flat(:r,:rf), lst.cat(:hf,:rf,:l);

}

// eliminate all consecutive duplicate of items in the list
lst.zip {

    ([],[])^                :- true;
    ([:e],[:e])^            :- true;
    ([:e,:e|:r],:l)         :- #lst.zip([:e|:r],:l);
    ([:e,:f|:r],[:e|:l])    :- neq(:e,:f), #lst.zip([:f|:r],:l);

}

// pack all consecutive duplicate of items in the list into sublists
lst.pack {

    ([],[])^            :- true;
    ([:h|:r],[:h2|:l])  :- #lst.pack.transfer(:h,:r,:l2,:h2), #lst.pack(:l2,:l);
}


// transfers items into sublists
lst.pack.transfer {

    (:h,[],[],[:h]);
    (:h,[:Y|:l2],[:Y|:l2],[:h]) :- neq(:h,:Y);
    (:h,[:h|:r],:l2,[:h|:l])    :- #lst.pack.transfer(:h,:r,:l2,:l);

}

// run-length encode a list
lst.encode {

    (:li,:lo) :- #lst.pack(:li,:lp), #lst.encode.packed(:lp,:lo);

}

// run-length encode a packed list
lst.encode.packed {

    ([],[])^            :- true;
    ([:e],[:ec])^       :- #lst.encode.compress(:e,:ec);
    ([:h|:r],[:hc|:ro]) :- #lst.encode.compress(:h,:hc), #lst.encode.packed(:r,:ro);
}

// compress a list of duplicates elements by return a tuple (length, element)
lst.encode.compress {

    ([],[])^        :- true;
    (:l,[:c,:h])    :- lst.length(:l,:c), lst.head(:l,:h);

}

// run-length encode a list (but keep non-consecutive elements as they were)
lst.encode2 {

    (:li,:lo) :- #lst.pack(:li,:lp), #lst.encode2.packed(:lp,:lo);

}

// run-length encode a packed list
lst.encode2.packed {

    ([],[])^            :- true;
    ([:e],[:ec])^       :- #lst.encode2.compress(:e,:ec);
    ([:h|:r],[:hc|:ro]) :- #lst.encode2.compress(:h,:hc), #lst.encode2.packed(:r,:ro);
}

// compress a list of duplicates elements by return a tuple (length, element) if there's duplicates
lst.encode2.compress {

    ([],[])^        :- true;
    ([:e],:e)^      :- true;
    (:l,[:c,:h])    :- lst.length(:l,:c), lst.head(:l,:h);

}

// decode a run-length encoded list
lst.decode {

    ([],[])^        :- true;
    ([:e],:ed)^     :- #lst.decode.decompress(:e,:ed);
    ([:h|:r],:l)    :- #lst.decode.decompress(:h,:hd), #lst.decode(:r,:rd), lst.cat(:hd,:rd,:l);

}

// decompress a list of duplicated elements
lst.decode.decompress {

    ([],[])^            :- true;
    (:e,:e)             :- !is.list(:e)^;
    ([1,:e],:e)^        :- true;
    ([:c,:e],[:e|:r])   :- sub(:c,1,:ci), #lst.decode.decompress([:ci,:e],:r);

}

// remove every nth elements from the list
lst.drop {

    ([],_,[])^                  :- true;
    (_,1,[])^                   :- true;
    (:li,:c,:lo)^               :- #lst.drop(:li,:c,:lo,:c);

    ([],_,[],_)^                :- true;
    ([_|:r],:c,:lo,1)^          :- #lst.drop(:r,:c,:lo,:c);
    ([:h|:r],:c,[:h|:r2],:k)    :- sub(:k,1,:k1), #lst.drop(:r,:c,:r2,:k1);
}

// split a list in two given the expected number of element in the first output list
lst.split {

    ([],_,[],[])^               :- true;
    ([:e],_,[:e],[])^           :- true;
    ([:h|:r],1,[:h],:r)^        :- true;
    ([:h|:r],:c,[:h|:l1],:l2)   :- sub(:c,1,:c1), #lst.split(:r,:c1,:l1,:l2);

}

// slice a part of a list based on a starting & ending index
lst.slice {

    ([],_,_,[])^                    :- true;
    ([:h|_],1,1,[:h])^              :- true;
    ([:h|:t],1,:k?[gt(1)],[:h|:t2]) :- sub(:k,1,:k1), #lst.slice(:t,1,:k1,:t2);
    ([_|:t],:i?[gt(1)],:k,:ts)      :- sub(:i,1,:i1), sub(:k,1,:k1), #lst.slice(:t,:i1,:k1,:ts);

}

// rotate a list by n elements (left or right)
lst.rotate {

    (:l1,:n?[gte(0)],:l2)^  :- lst.length(:l1,:nl1), mod(:n,:nl1,:n1), #lst.rotate.left(:l1,:n1,:l2);
    (:l1,:n?[lt(0)],:l2)    :- lst.length(:l1,:nl1), sub(:nl1,:n,:n1), #lst.rotate(:l1,:n1,:l2);

}

// rotate a list content left by n elements
lst.rotate.left {

    (:l,0,:l)^              :- true;
    (:l1,:n?[gt(0)],:l2)    :- #lst.split(:l1,:n,:s1,:s2), lst.cat(:s2,:s1,:l2);

}

// ---------------------------------------------------------------------------------------------------------------------------------------

[Home] [Email] [Twitter] [LinkedIn]