All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ceylon.language.SearchableList.ceylon Maven / Gradle / Ivy

There is a newer version: 1.3.3
Show newest version
"A [[List]] which can be efficiently searched for 
 occurrences of a given element, or for inclusions of a 
 given sublist of elements. This interface provides 
 operations for finding:
 
 - _occurrences_ of a single value in the list, and
 - _inclusions_ of a given sublist of values in the list.
 
 Occurrences and inclusions are identified by a list index
 at which the value or sublist of values occurs in the list. 
 In the case of an inclusion, it is the index of the first 
 matching value from the sublist.
 
 Inclusions may overlap. For example:
 
     \"yoyoyoyoyo\".inclusions(\"yoy\")
 
 produces the stream `{ 0, 2, 4, 6 }`.
 
 An empty list is considered to be included at every index,
 including the index [[size]] at the very end of the 
 list. Thus:
 
     \"hello\".inclusions(\"\")
 
 produces the stream `{ 0, 1, 2, 3, 4, 5 }`, with 6 
 inclusions in a string of length 5. 
 
 In particular:
 
 - `\"\".inclusions(\"x\")` is the empty stream `{}`, but
 - `\"\".inclusions(\"\")` is the stream `{ 0 }`."
see (`class String`, `class Array`)
since("1.2.0")
shared interface SearchableList 
        satisfies List {
    
    "Determines if the given [[value|element]] occurs at the 
     given index in this list."
    shared default 
    Boolean occursAt(
        "The index at which the value might occur."
        Integer index, 
        "The value. If null, it is considered to occur
         at any index in this list with a null element."
        Element element)
            => let (elem = getFromFirst(index))
            if (exists element, exists elem) 
            then elem == element 
            else (0 <= index < size)
                && !element exists && !elem exists;
    
    "The indexes in this list at which the given 
     [[value|element]] occurs."
    shared default 
    {Integer*} occurrences(
        "The value. If null, it is considered to occur
         at any index in this list with a null element."
        Element element,
        "The smallest index to consider."
        Integer from = 0,
        "The number of indexes to consider."
        Integer length = size-from)
            //performance of comprehension was 
            //worse than hand-written iterable
            //=> { for (i in from:length) 
            //     if (occursAt(i, element)) i };
            => object satisfies Iterable {
        value len = outer.size;
        value max = 
                from+length>len 
                    then len else from+length;
        iterator() 
                => object satisfies Iterator {
            variable value index = from;
            shared actual Integer|Finished next() {
                while (index occurs(element, from, length);
        first => firstOccurrence(element, from, length);
        last => lastOccurrence(element, from, length);
    };
    
    "Determines if the given [[value|element]] occurs as an 
     element of this list, at any index that falls within
     the segment `from:length` defined by the optional 
     [[starting index|from]] and [[length]]."
    shared default 
    Boolean occurs(
        "The value. If null, it is considered to occur
         at any index in this list with a null element."
        Element element,
        "The smallest index to consider."
        Integer from = 0,
        "The number of indexes to consider."
        Integer length = size-from)
            => firstOccurrence(element, from, length) exists;
    
    "The first index in this list at which the given 
     [[value|element]] occurs, that falls within the segment 
     `from:length` defined by the optional 
     [[starting index|from]] and [[length]]."
    shared default 
    Integer? firstOccurrence(
        "The value. If null, it is considered to occur
         at any index in this list with a null element."
        Element element,
        "The smallest index to consider."
        variable Integer from = 0,
        "The number of indexes to consider."
        variable Integer length = size-from) {
        if (from < 0) {
            length += from;
            from = 0;
        }
        if (length > size - from) {
            length = size - from;
        }
        for (index in from:length) {
            if (occursAt(index,element)) {
                return index;
            }
        }
        else {
            return null;
        }
    }
    
    "The last index in this list at which the given 
     [[value|element]] occurs, that falls within the range 
     `size-length-from:length` defined by the optional 
     [[starting index|from]], interpreted as a reverse index 
     counting from the _end_ of the list, and [[length]]."
    shared default 
    Integer? lastOccurrence(
        "The value. If null, it is considered to occur
         at any index in this list with a null element."
        Element element,
        "The smallest index to consider, interpreted as
         a reverse index counting from the _end_ of the 
         list, where `0` is the last element of the list, 
         and `size-1` is the first element of the list."
        variable Integer from = 0,
        "The number of indexes to consider."
        variable Integer length = size-from) {
        //TODO: refine reversed to return a SearchableList
        // => reversed.firstOccurrence(element, from, length)
        if (from < 0) {
            length += from;
            from = 0;
        }
        if (length > size - from) {
            length = size - from;
        }
        for (index in (size-length-from:length).reversed) {
            if (occursAt(index,element)) {
                return index;
            }
        }
        else {
            return null;
        }
    }
    
    "Determine if the given [[list|sublist]] occurs as a 
     sublist at the given index of this list."
    shared default 
    Boolean includesAt(
        "The index at which the [[sublist]] might occur."
        Integer index, 
        List sublist) {
        if (0 <= index <= size-sublist.size) {
            variable value i = index;
            for (element in sublist) {
                if (exists element) {
                    if (!occursAt(i, element)) {
                        return false;
                    }
                }
                else {
                    assert (is Element null);
                    if (!occursAt(i, null)) {
                        return false;
                    }
                }
                i++;
            }
            else {
                return true;
            }
        }
        else {
            return false;
        }
    }
    
    "The indexes in this list at which the given 
     [[list|sublist]] occurs as a sublist, that are greater 
     than or equal to the optional [[starting index|from]]."
    shared default 
    {Integer*} inclusions(List sublist,
        "The smallest index to consider." 
        Integer from = 0) 
            //performance of comprehension was 
            //worse than hand-written iterable
            /*=> { for (i in from:size+1-from-sublist.size) 
                 if (includesAt(i, sublist)) i };*/
            => object satisfies Iterable {
        value len = outer.size;
        iterator() 
                => object satisfies Iterator {
            value max = len+1-sublist.size;
            variable value index = from;
            shared actual Integer|Finished next() {
                while (index includes(sublist, from);
        first => firstInclusion(sublist, from);
        last => lastInclusion(sublist, from);
    };
    
    "Determine if the given [[list|sublist]] occurs as a 
     sublist at some index in this list, at any index that 
     is greater than or equal to the optional 
     [[starting index|from]]."
    shared default 
    Boolean includes(List sublist,
        "The smallest index to consider."
        Integer from = 0) 
            => firstInclusion(sublist, from) exists;
        
    "The first index in this list at which the given 
     [[list|sublist]] occurs as a sublist, that is greater 
     than or equal to the optional [[starting index|from]]."
    shared default 
    Integer? firstInclusion(List sublist,
        "The smallest index to consider." 
        Integer from = 0) {
        for (index in from:size-from+1-sublist.size) {
            if (includesAt(index,sublist)) {
                return index;
            }
        }
        else {
            return null;
        }
    }
    
    "The last index in this list at which the given 
     [[list|sublist]] occurs as a sublist, that falls within 
     the range `0:size-from+1-sublist.size` defined by the 
     optional [[starting index|from]], interpreted as a 
     reverse index counting from the _end_ of the list."
    shared default 
    Integer? lastInclusion(List sublist,
        "The smallest index to consider, interpreted as
         a reverse index counting from the _end_ of the 
         list, where `0` is the last element of the list, 
         and `size-1` is the first element of the list."
        Integer from = 0) {
        //TODO: refine reversed to return a SearchableList
        // => reversed.firstInclusion(element, from, length)
        for (index in (0:size-from+1-sublist.size).reversed) {
            if (includesAt(index,sublist)) {
                return index;
            }
        }
        else {
            return null;
        }
    }
    
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy