Skip to content

Instantly share code, notes, and snippets.

@Phryxia
Last active March 10, 2024 04:01
Show Gist options
  • Save Phryxia/a94200ef46ad42eb45b250a8730fe32f to your computer and use it in GitHub Desktop.
Save Phryxia/a94200ef46ad42eb45b250a8730fe32f to your computer and use it in GitHub Desktop.
TypeScript implementation of Infinite Dimension Array
type RecursiveArray<T> = (T | RecursiveArray<T>)[]
type UtilizedRecursiveArray<T> = RecursiveArray<T> & {
get(...indices: number[]): T | RecursiveArray<T>
set(value: T, ...indices: number[]): T
}
function utilize<T>(rarr: RecursiveArray<T>): UtilizedRecursiveArray<T> {
const res = rarr as any
res.get = (...indices: number[]) => {
let el: T | RecursiveArray<T> = res
for (const index of indices) {
if ((el as Array<any>)?.length == null) {
throw new Error(`There is no array in given index (${indices.join(', ')})`)
}
el = (el as RecursiveArray<T>)[index]
}
return el
}
res.set = (value: T, ...indices: number[]) => {
let el: T | RecursiveArray<T> = res
for (let i = 0; i < indices.length; ++i) {
const index = indices[i]
if (i === indices.length - 1) {
(el as RecursiveArray<T>)[index] = value
break
}
let child = (el as RecursiveArray<T>)[index]
if (child === undefined) {
child = (el as RecursiveArray<T>)[index] = []
} else if ((child as Array<any>)?.length == null) {
throw new Error(`There is already a non array element in index (${indices.join(', ')})`)
}
el = child as RecursiveArray<T>
}
return value
}
return res
}
@Phryxia
Copy link
Author

Phryxia commented Mar 10, 2024

Example

const deepArray =  utilize([1, [5, 3], [[4], 0]])

deepArray.get(2, 0, 0) // 4
deepArray.set(10, 1, 2) // now deepArray is [1, [5, 10], [[4], 0]])

Caveat

Don't use type undefined for type parameter T in UtilizedRecursiveArray<T>. There is no way to distinguish intended value or actual non existence of such array, in line 26. If you want to use, you have to give up for dynamic array creation during new indices path.

// Alternative implementation of set, to support `undefined` as their element
res.set = (value: T, ...indices: number[]) => {
  let el: T | RecursiveArray<T> = res
  for (let i = 0; i < indices.length; ++i) {
      const index = indices[i]

      if (i === indices.length - 1) {
          (el as RecursiveArray<T>)[index] = value
          break
      }

      let child = (el as RecursiveArray<T>)[index]

      if ((child as Array<any>)?.length == null) {
          throw new Error(`There is already a non array element in index (${indices.join(', ')})`)
      }
      el = child as RecursiveArray<T>
  }
  return value
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment