Skip to content

Commit 4a15b95

Browse files
committed
Refactor xlookupArraySize function
1 parent 3135c28 commit 4a15b95

File tree

2 files changed

+65
-60
lines changed

2 files changed

+65
-60
lines changed

src/interpreter/plugin/LookupPlugin.ts

Lines changed: 20 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -149,54 +149,37 @@ export class LookupPlugin extends FunctionPlugin implements FunctionPluginTypech
149149
})
150150
}
151151

152-
public xlookupArraySize(ast: ProcedureAst, state: InterpreterState): ArraySize {
153-
const lookupRangeValue = ast?.args?.[1] as CellRange
154-
const returnRangeValue = ast?.args?.[2] as CellRange
155-
156-
if (lookupRangeValue == null
157-
|| lookupRangeValue.start == null
158-
|| lookupRangeValue.end == null
159-
|| returnRangeValue == null
160-
|| returnRangeValue.start == null
161-
|| returnRangeValue.end == null
162-
) {
163-
return ArraySize.error()
164-
}
152+
public xlookupArraySize(ast: ProcedureAst): ArraySize {
153+
const lookupRange = ast?.args?.[1] as CellRange
154+
const returnRange = ast?.args?.[2] as CellRange
155+
156+
// co tu wpada jesli argumenty to single-cell range?
165157

166-
if (!this.areRangesShapeValidForXlookup(lookupRangeValue, returnRangeValue)) {
158+
if (lookupRange?.start == null
159+
|| lookupRange?.end == null
160+
|| returnRange?.start == null
161+
|| returnRange?.end == null
162+
) {
167163
return ArraySize.error()
168164
}
169165

170-
const searchWidth = lookupRangeValue.end.col - lookupRangeValue.start.col + 1
166+
const lookupRangeHeight = lookupRange.end.row - lookupRange.start.row + 1
167+
const lookupRangeWidth = lookupRange.end.col - lookupRange.start.col + 1
168+
const returnRangeHeight = returnRange.end.row - returnRange.start.row + 1
169+
const returnRangeWidth = returnRange.end.col - returnRange.start.col + 1
171170

172-
if (returnRangeValue?.start == null || returnRangeValue?.end == null) {
173-
return ArraySize.scalar()
174-
}
171+
const isVerticalSearch = lookupRangeWidth === 1 && returnRangeHeight === lookupRangeHeight
172+
const isHorizontalSearch = lookupRangeHeight === 1 && returnRangeWidth === lookupRangeWidth
175173

176-
if (searchWidth === 1) {
177-
// column search
178-
const outputWidth = returnRangeValue.end.col - returnRangeValue.start.col + 1
179-
return new ArraySize(outputWidth, 1)
180-
} else {
181-
// row search
182-
const outputHeight = returnRangeValue.end.row - returnRangeValue.start.row + 1
183-
return new ArraySize(1, outputHeight)
174+
if (!isVerticalSearch && !isHorizontalSearch) {
175+
return ArraySize.error()
184176
}
185-
}
186-
187-
private areRangesShapeValidForXlookup(lookupRange: CellRange, returnRange: CellRange): boolean {
188-
const isVerticalSearch = lookupRange.start.col === lookupRange.end.col && lookupRange.start.row <= lookupRange.end.row
189-
const isHorizontalSearch = lookupRange.start.row === lookupRange.end.row && lookupRange.start.col <= lookupRange.end.col
190177

191178
if (isVerticalSearch) {
192-
return lookupRange.end.row - lookupRange.start.row === returnRange.end.row - returnRange.start.row
179+
return new ArraySize(returnRangeWidth, 1)
193180
}
194181

195-
if (isHorizontalSearch) {
196-
return lookupRange.end.col - lookupRange.start.col === returnRange.end.col - returnRange.start.col
197-
}
198-
199-
return false
182+
return new ArraySize(1, returnRangeHeight)
200183
}
201184

202185
public match(ast: ProcedureAst, state: InterpreterState): InterpreterValue {
@@ -295,7 +278,6 @@ export class LookupPlugin extends FunctionPlugin implements FunctionPluginTypech
295278
return SimpleRangeValue.onlyValues(returnValues)
296279
}
297280

298-
299281
private doMatch(key: RawNoErrorScalarValue, rangeValue: SimpleRangeValue, type: number): InternalScalarValue {
300282
if (![-1, 0, 1].includes(type)) {
301283
return new CellError(ErrorType.VALUE, ErrorMessage.BadMode)

test/interpreter/function-xlookup.spec.ts

Lines changed: 45 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,8 @@ describe('Function XLOOKUP', () => {
139139

140140
expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.ValueNotFound))
141141
expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.ValueNotFound))
142-
expect(engine.getCellValue(adr('A3'))).toEqual("not found")
143-
expect(engine.getCellValue(adr('A4'))).toEqual("not found")
142+
expect(engine.getCellValue(adr('A3'))).toEqual('not found')
143+
expect(engine.getCellValue(adr('A4'))).toEqual('not found')
144144
})
145145

146146
it('works when returnArray is shifted (verical search)', () => {
@@ -172,24 +172,45 @@ describe('Function XLOOKUP', () => {
172172
expect(engine.getCellValue(adr('A1'))).toEqual('b')
173173
})
174174

175-
it('works when lookupArray is a single cell', () => {
176-
const engine = HyperFormula.buildFromArray([
177-
['=XLOOKUP(1, B1:B1, C1:C1)', 1, 'a', 'horizontal'], // lookupArray: single cell, returnArray: single cell
178-
['=XLOOKUP(1, B1, C1:C1)', '', 'vertical'], // lookupArray: single cell, returnArray: single cell
179-
['=XLOOKUP(1, B1:B1, C1:C2)'], // lookupArray: single cell, returnArray: vertical range
180-
[],
181-
['=XLOOKUP(1, B1, C1:C2)'], // lookupArray: single cell, returnArray: vertical range
182-
[],
183-
['=XLOOKUP(1, B1:B1, C1:D1)'], // lookupArray: single cell, returnArray: horizontal range
184-
['=XLOOKUP(1, B1, C1:D1)'], // lookupArray: single cell, returnArray: horizontal range
185-
])
186-
187-
expect(engine.getCellValue(adr('A1'))).toEqual('a')
188-
expect(engine.getCellValue(adr('A2'))).toEqual('a')
189-
expect(engine.getRangeValues(AbsoluteCellRange.spanFrom(adr('A3'), 1, 2))).toEqual([['a'], ['vertical']])
190-
expect(engine.getRangeValues(AbsoluteCellRange.spanFrom(adr('A5'), 1, 2))).toEqual([['a'], ['vertical']])
191-
expect(engine.getRangeValues(AbsoluteCellRange.spanFrom(adr('A7'), 2, 1))).toEqual([['a', 'horizontal']])
192-
expect(engine.getRangeValues(AbsoluteCellRange.spanFrom(adr('A8'), 2, 1))).toEqual([['a', 'horizontal']])
175+
describe('when lookupArray is a single cell', () => {
176+
it('works when returnArray is also a single cell', () => {
177+
const engine = HyperFormula.buildFromArray([
178+
['=XLOOKUP(1, B1:B1, C1:C1)', 1, 'a'],
179+
['=XLOOKUP(1, B1, C1:C1)'],
180+
])
181+
182+
expect(engine.getCellValue(adr('A1'))).toEqual('a')
183+
expect(engine.getCellValue(adr('A2'))).toEqual('a')
184+
})
185+
186+
it('works when returnArray is a vertical range', () => {
187+
const engine = HyperFormula.buildFromArray([
188+
['=XLOOKUP(1, B1:B1, A5:A6)', 1],
189+
[],
190+
['=XLOOKUP(1, B1, A5:A6)'],
191+
[],
192+
['b'],
193+
['c']
194+
])
195+
196+
expect(engine.getCellValue(adr('A1'))).toEqual('b')
197+
expect(engine.getCellValue(adr('A2'))).toEqual('c')
198+
expect(engine.getCellValue(adr('A3'))).toEqual('b')
199+
expect(engine.getCellValue(adr('A4'))).toEqual('c')
200+
})
201+
202+
it('works when returnArray is a horizontal range', () => {
203+
const engine = HyperFormula.buildFromArray([
204+
[1, 'b', 'c'],
205+
['=XLOOKUP(1, A1:A1, B1:C1)'],
206+
['=XLOOKUP(1, A1, B1:C1)'],
207+
])
208+
209+
expect(engine.getCellValue(adr('A2'))).toEqual('b')
210+
expect(engine.getCellValue(adr('B2'))).toEqual('c')
211+
expect(engine.getCellValue(adr('A3'))).toEqual('b')
212+
expect(engine.getCellValue(adr('B3'))).toEqual('c')
213+
})
193214
})
194215

195216
it('finds an empty cell', () => {
@@ -294,5 +315,7 @@ describe('Function XLOOKUP', () => {
294315
})
295316

296317
// TODO:
297-
// - single cell
298-
// - modes
318+
// - debugger
319+
// - review arraysize function
320+
// - fix single cell
321+
// - implementmodes

0 commit comments

Comments
 (0)