Home > Back-end >  Recursive function to return overall overall results
Recursive function to return overall overall results

Time:12-04

I need a recursive method to roll up all results from a series of paginated calls and returns the complete list of results. Something feels off in the way I am doing it and feel there is a better way to do this, possibly with Array.reduce

Any recommendations appreciated.

interface Result {
  users: Widget[];
  start: number;
}

interface Widget {
  id: number;
}

// create 3 widgets for test
const widgets = Array(3).fill(null).map((i, index: number) => {
  return {
    id: index   1,
  } as Widget;
});

const getFromAPI = (start: number = 0): Result => {
  // return 1 at a time from a specified position
  const current = widgets.slice(start, start   1);
  let nextStart: number | undefined;
  if (start < widgets.length - 1) {
    nextStart = start   1;
  }

  return {
    users: current,
    start: nextStart,
  }
}

// I don't like that em is outside the scope here
let em: Widget[] = [];
const getWidgets = (start?: number): Widget[] => {
  const result = getFromAPI(start);
  em = [...em, ...result.users];
  if (result.start) {
    getWidgets(result.start);
  }

  return em;
}

const all = getWidgets();

CodePudding user response:

You don't like that em is outside the scope of getWidget() and that you are reassigning it inside the function body and thus relying on side effects. Instead it seems that you want something more purely functional, without relying on state changes.

If so, then one approach you can take is to make em another argument to the function, and have it initially empty, and then returning the recursive result of getWidgets() called with the next version of em:

const getWidgets = (em: Widget[] = [], start?: number): Widget[] => {
  const result = getFromAPI(start);
  const nextEm = [...em, ...result.users];
  return result.start ? getWidgets(nextEm, result.start) : nextEm;
}

I've changed the reassignment of em to a new variable nextEm just in case you want to avoid side effects even within the body of getWidgets as well. It makes the algorithm a little clearer anyway.

You can verify that a call to getWidgets() yields the same result as in your example:

const all = getWidgets();
console.log(all); // [{ "id": 1}, { "id": 2}, { "id": 3}] 

Playground link to code

  • Related