Skip to content

Commit

Permalink
Version 6; remove FILTER, SORT, UNIQUE, XLOOKUP; update README
Browse files Browse the repository at this point in the history
  • Loading branch information
goosepirate committed Nov 6, 2024
1 parent 350a671 commit a0ee78d
Show file tree
Hide file tree
Showing 9 changed files with 32 additions and 324 deletions.
47 changes: 30 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# ⚗️ Lox365: XLOOKUP for LibreOffice
# ⚗️ Lox365: Modern functions for LibreOffice

Lox365 is a LibreOffice Calc extension that adds modern spreadsheet functions like XLOOKUP, FILTER, and more.
Lox365 is a LibreOffice Calc extension that adds modern spreadsheet functions like IMAGE, TEXTSPLIT, and TOCOL.

![Screenshot](image1.png)
![Screenshot](image9.png)

![Screenshot](image2.png)
![Screenshot](image4.png)

Do you like using Lox365? Let me know in the [Discussions](https://github.com/goosepirate/lox365/discussions). Maybe [buy me a coffee](https://liberapay.com/goosepirate/).

Expand All @@ -29,7 +29,7 @@ This is because Lox365 functions are [array functions](https://help.libreoffice.

### Syntax

#### FILTER
#### ~~FILTER~~ (Removed)

Filters an array.

Expand Down Expand Up @@ -63,7 +63,7 @@ Similar to Excel's [IMAGE](https://support.microsoft.com/en-us/office/image-func
* `out_cell`: Reference to the cell where the image is to be placed.
* `source`: The path of the source that points to the image.

#### SORT
#### ~~SORT~~ (Removed)

Sorts an array.

Expand Down Expand Up @@ -102,7 +102,7 @@ Similar to Excel's [TOCOL](https://support.microsoft.com/en-us/office/tocol-func
* `array`: The array to return as a column.
* Not supported: `ignore`, `scan_by_column`.

#### UNIQUE
#### ~~UNIQUE~~ (Removed)

Returns the unique values from a range or array.

Expand All @@ -114,7 +114,7 @@ Similar to Excel's [UNIQUE](https://support.microsoft.com/en-us/office/unique-fu
* `array`: The array from which to return unique rows.
* Not supported: `by_col`, `exactly_once`.

#### XLOOKUP
#### ~~XLOOKUP~~ (Removed)

Searches an array for a match and returns the corresponding item from a second array.

Expand All @@ -129,6 +129,15 @@ Similar to Excel's [XLOOKUP](https://support.microsoft.com/en-us/office/xlookup-
* `[if_not_found]`: Where a valid match is not found, return the [if_not_found] text you supply. Optional.
* Not supported: `match_mode`, `search_mode`.

## Version notes

These functions have been removed in Lox365 version 6 because you can now use them in the latest LibreOffice (24.8):

* FILTER
* SORT
* UNIQUE
* XLOOKUP

## Why

I use these functions quite often in Excel and wanted to use them in LibreOffice too, so I made this.
Expand Down Expand Up @@ -203,25 +212,29 @@ On a machine without Lox365 installed, you will not be able to view calculation

These functions are not in LibreOffice and not provided by Lox365 but are available in the latest Excel:

* RANDARRAY
* SEQUENCE
* SORTBY
* GROUPBY
* LAMBDA
* PIVOTBY
* STOCKHISTORY
* TOROW
* XMATCH

These functions are not in LibreOffice Calc now, but are planned to be added:

* XLOOKUP

These functions are already available in LibreOffice:
These functions are available in the latest LibreOffice:

* CONCAT
* FILTER
* IFS
* LET
* MAXIFS
* MINIFS
* RANDARRAY
* SEQUENCE
* SORT
* SORTBY
* SWITCH
* TEXTJOIN
* UNIQUE
* XLOOKUP
* XMATCH

## References

Expand Down
72 changes: 0 additions & 72 deletions addin.xcu
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,6 @@
<node oor:name="AddInInfo">
<node oor:name="com.goosepirate.lox365.oxt" oor:op="replace">
<node oor:name="AddInFunctions">
<node oor:name="FILTER" oor:op="replace">
<prop oor:name="DisplayName"><value xml:lang="en">FILTER</value></prop>
<prop oor:name="Description"><value xml:lang="en">Filters an array. Provided by Lox365.</value></prop>
<prop oor:name="Category"><value>Add-in</value></prop>
<node oor:name="Parameters">
<node oor:name="array" oor:op="replace">
<prop oor:name="DisplayName"><value xml:lang="en">Array</value></prop>
<prop oor:name="Description"><value xml:lang="en">The array to filter.</value></prop>
</node>
<node oor:name="include" oor:op="replace">
<prop oor:name="DisplayName"><value xml:lang="en">Include</value></prop>
<prop oor:name="Description"><value xml:lang="en">An array of booleans where TRUE represents a row or column to retain.</value></prop>
</node>
<node oor:name="ifEmpty" oor:op="replace">
<prop oor:name="DisplayName"><value xml:lang="en">[If empty]</value></prop>
<prop oor:name="Description"><value xml:lang="en">Returned if no items are retained.</value></prop>
</node>
</node>
</node>
<node oor:name="IMAGE" oor:op="replace">
<prop oor:name="DisplayName"><value xml:lang="en">IMAGE</value></prop>
<prop oor:name="Description"><value xml:lang="en">Returns an image from a given source. Provided by Lox365.</value></prop>
Expand All @@ -39,25 +20,6 @@
</node>
</node>
</node>
<node oor:name="SORT" oor:op="replace">
<prop oor:name="DisplayName"><value xml:lang="en">SORT</value></prop>
<prop oor:name="Description"><value xml:lang="en">Sorts an array. Provided by Lox365.</value></prop>
<prop oor:name="Category"><value>Add-in</value></prop>
<node oor:name="Parameters">
<node oor:name="array" oor:op="replace">
<prop oor:name="DisplayName"><value xml:lang="en">Array</value></prop>
<prop oor:name="Description"><value xml:lang="en">The array to sort.</value></prop>
</node>
<node oor:name="sortIndex" oor:op="replace">
<prop oor:name="DisplayName"><value xml:lang="en">[Sort index]</value></prop>
<prop oor:name="Description"><value xml:lang="en">A number indicating the row or column to sort by.</value></prop>
</node>
<node oor:name="sortOrder" oor:op="replace">
<prop oor:name="DisplayName"><value xml:lang="en">[Sort order]</value></prop>
<prop oor:name="Description"><value xml:lang="en">A number indicating the desired sort order; 1 for ascending order (default), -1 for descending order.</value></prop>
</node>
</node>
</node>
<node oor:name="TEXTSPLIT" oor:op="replace">
<prop oor:name="DisplayName"><value xml:lang="en">TEXTSPLIT</value></prop>
<prop oor:name="Description"><value xml:lang="en">Splits text into columns using delimiters. Provided by Lox365.</value></prop>
Expand All @@ -84,40 +46,6 @@
</node>
</node>
</node>
<node oor:name="UNIQUE" oor:op="replace">
<prop oor:name="DisplayName"><value xml:lang="en">UNIQUE</value></prop>
<prop oor:name="Description"><value xml:lang="en">Returns the unique values from a range or array. Provided by Lox365.</value></prop>
<prop oor:name="Category"><value>Add-in</value></prop>
<node oor:name="Parameters">
<node oor:name="array" oor:op="replace">
<prop oor:name="DisplayName"><value xml:lang="en">Array</value></prop>
<prop oor:name="Description"><value xml:lang="en">The array from which to return unique rows.</value></prop>
</node>
</node>
</node>
<node oor:name="XLOOKUP" oor:op="replace">
<prop oor:name="DisplayName"><value xml:lang="en">XLOOKUP</value></prop>
<prop oor:name="Description"><value xml:lang="en">Searches an array for a match and returns the corresponding item from a second array. Provided by Lox365.</value></prop>
<prop oor:name="Category"><value>Add-in</value></prop>
<node oor:name="Parameters">
<node oor:name="lookupValue" oor:op="replace">
<prop oor:name="DisplayName"><value xml:lang="en">Lookup value</value></prop>
<prop oor:name="Description"><value xml:lang="en">The value to search for.</value></prop>
</node>
<node oor:name="lookupArray" oor:op="replace">
<prop oor:name="DisplayName"><value xml:lang="en">Lookup array</value></prop>
<prop oor:name="Description"><value xml:lang="en">The array to search.</value></prop>
</node>
<node oor:name="returnArray" oor:op="replace">
<prop oor:name="DisplayName"><value xml:lang="en">Return array</value></prop>
<prop oor:name="Description"><value xml:lang="en">The array to return.</value></prop>
</node>
<node oor:name="ifNotFound" oor:op="replace">
<prop oor:name="DisplayName"><value xml:lang="en">[If not found]</value></prop>
<prop oor:name="Description"><value xml:lang="en">Where a valid match is not found, return the [if_not_found] text you supply.</value></prop>
</node>
</node>
</node>
</node>
</node>
</node>
Expand Down
2 changes: 1 addition & 1 deletion description.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
xmlns:xlink="http://www.w3.org/1999/xlink">
<identifier value="com.goosepirate.lox365.oxt" />
<icon><default xlink:href="icon.png" /></icon>
<version value="5.0" />
<version value="6.0" />
<publisher><name xlink:href="https://github.com/goosepirate/lox365" lang="en">goosepirate</name></publisher>
<display-name><name lang="en">Lox365</name></display-name>
<extension-description><src xlink:href="extension-description.txt" lang="en"/></extension-description>
Expand Down
2 changes: 1 addition & 1 deletion extension-description.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Lox365: XLOOKUP for LibreOffice
Lox365: Modern functions for LibreOffice
19 changes: 0 additions & 19 deletions interface.idl
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,17 @@

module org { module openoffice { module sheet { module addin {
interface XLox365 : com::sun::star::uno::XInterface {
sequence< sequence< any > > FILTER(
[in] sequence< sequence< any > > array,
[in] sequence< sequence< any > > include,
[in] any ifEmpty
);
any IMAGE(
[in] com::sun::star::beans::XPropertySet doc,
[in] com::sun::star::table::XCellRange out_cell,
[in] string url
);
sequence< sequence< any > > SORT(
[in] sequence< sequence< any > > array,
[in] any sortIndex,
[in] any sortOrder
);
sequence< sequence< any > > TEXTSPLIT(
[in] string text,
[in] string colDelimiter
);
sequence< sequence< any > > TOCOL(
[in] sequence< sequence< any > > array
);
sequence< sequence< any > > UNIQUE(
[in] com::sun::star::table::XCellRange array
);
sequence< sequence< any > > XLOOKUP(
[in] any lookupValue,
[in] com::sun::star::table::XCellRange lookupArray,
[in] com::sun::star::table::XCellRange returnArray,
[in] any ifNotFound
);
};
}; }; }; };
23 changes: 0 additions & 23 deletions loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,33 +37,10 @@ def _get_shrunk_corners(self, cellrange) -> dict:
}
return useful_positions

def FILTER (self, *args): return lx.FILTER (*args)
def IMAGE (self, *args): return lx.IMAGE (*args)
def SORT (self, *args): return lx.SORT (*args)
def TEXTSPLIT(self, *args): return lx.TEXTSPLIT(*args)
def TOCOL (self, *args): return lx.TOCOL (*args)

def UNIQUE(self, *args):
shrunk_corners = self._get_shrunk_corners(args[0])
shrunk_dataarray = self._get_dataarray(args[0], shrunk_corners)
args = (shrunk_dataarray,)
return lx.UNIQUE(*args)

def XLOOKUP(self, *args):
shrunk_corners1 = self._get_shrunk_corners(args[1])
shrunk_corners2 = self._get_shrunk_corners(args[2])
shrunk_corners_common_bottom = max(
shrunk_corners1['bottom'], shrunk_corners2['bottom'])
shrunk_dataarray1 = self._get_dataarray(args[1], {
'left': 0, 'top': 0,
'right': shrunk_corners1['right'],
'bottom': shrunk_corners_common_bottom})
shrunk_dataarray2 = self._get_dataarray(args[2], {
'left': 0, 'top': 0,
'right': shrunk_corners2['right'],
'bottom': shrunk_corners_common_bottom})
args = (args[0], shrunk_dataarray1, shrunk_dataarray2, *args[3:],)
return lx.XLOOKUP(*args)

def createInstance(ctx):
return Lox365(ctx)
Expand Down
46 changes: 0 additions & 46 deletions pythonpath/lox365.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,11 @@
ERR_CALC = '#CALC!'
ERR_NA = '#N/A'

def FILTER(array, include, ifEmpty=ERR_CALC):
if ifEmpty is None: ifEmpty = ERR_CALC
lookup_direction = 0 # 0 is vertical; 1 is horizontal
if len(include) == 1 and len(include[0]) > 1: lookup_direction = 1
import itertools
if lookup_direction == 0:
ans = tuple(itertools.compress(array, [i[0] for i in include]))
if len(ans) == 1:
ans = (ans[0], tuple([0] * len(array[0])),)
else:
ans = tuple(tuple(itertools.compress(row, include[0])) for row in array)
return ans if ans else ((ifEmpty,),)

try:
import imagefn
IMAGE = imagefn.IMAGE
except ImportError: pass

def SORT(array, sortIndex=1, sortOrder=1):
if sortIndex is None: sortIndex = 1
if sortOrder is None or sortOrder == 1: reverse = False
elif sortOrder == -1: reverse = True
else: return ValueError
stringify = True
if all(isinstance(item[sortIndex - 1], float) for item in array):
stringify = False
return tuple(sorted(array,
key=lambda r: str(r[sortIndex - 1]) if stringify else r[sortIndex - 1],
reverse=reverse))

def TEXTSPLIT(text, colDelimiter):
if text == '' or text == '0': return ((0,),) # Compensate for when LO Calc converts a blank cell to a '0' string.
t2 = text.split(colDelimiter)
Expand All @@ -46,24 +21,3 @@ def TOCOL(array):
for item in row:
result.append((item,))
return tuple(result)

def UNIQUE(array):
return tuple(dict.fromkeys(array))

def XLOOKUP(lookupValue, lookupArray, returnArray, ifNotFound=ERR_NA):
if ifNotFound is None: ifNotFound = ERR_NA
lookup_direction = 0 # 0 is vertical; 1 is horizontal
if len(lookupArray) == 1 and len(lookupArray[0]) > 1: lookup_direction = 1
try:
if lookup_direction == 0:
return (returnArray[lookupArray.index((lookupValue,))],)
if lookup_direction == 1:
return tuple((row[lookupArray[0].index(lookupValue)],) for row in returnArray)
except ValueError: return ((ifNotFound,),)

# Too slow
# def XLOOKUP_old1(lookup_value, lookup_array, return_array, if_not_found):
# lookup_item = (lookup_value,)
# for index, item in enumerate(lookup_array):
# if item == lookup_item: return (return_array[index],)
# return ((if_not_found,),)
Loading

0 comments on commit a0ee78d

Please sign in to comment.