<commit_before>api.fn = {}

function api.fn.map(t, fn)
  local nt = {}
  for k, v in pairs(t) do
    table.insert(nt, fn(v) or nil)
  end
  return nt
end

function api.fn.filter(t, fn)
  local nt = {}
  for k, v in pairs(t) do
    if fn(v) then table.insert(nt, v) end
  end
  return nt
end

function api.fn.contains(t, el)
  for k, v in pairs(t) do
    if v == el then
      return true
    end
  end
  return false
end

function api.fn.indexof(t, el)
  for k, v in pairs(t) do
    if v == el then
      return k
    end
  end
  return nil
end

function api.fn.concat(t1, t2)
  -- NOTE: mutates t1!
  for i = 1, #t2 do
    t1[#t1 + 1] = t2[i]
  end
  return t1
end

function api.fn.mapcat(t, fn)
  local nt = {}
  for k, v in pairs(t) do
    api.fn.concat(nt, fn(v))
  end
  return nt
end

function api.fn.reduce(t, fn)
  local len = #t
  if len == 0 then return nil end
  if len == 1 then return t[1] end

  local result = t[1]
  for i = 2, #t do
    result = fn(result, t[i])
  end
  return result
end<commit_msg>Documenting api.fn API.<commit_after>api.fn = {}

api.doc.fn = {__doc = "Super-helpful functional programming utilities."}

api.doc.fn.map = {"api.fn.map(t, fn) -> t", "Returns a table of the results of t(el) on every el in t."}
function api.fn.map(t, fn)
  local nt = {}
  for k, v in pairs(t) do
    table.insert(nt, fn(v) or nil)
  end
  return nt
end

api.doc.fn.filter = {"api.fn.filter(t, fn) -> t", "Returns a table of the elements in t in which t(el) is truthy."}
function api.fn.filter(t, fn)
  local nt = {}
  for k, v in pairs(t) do
    if fn(v) then table.insert(nt, v) end
  end
  return nt
end

api.doc.fn.contains = {"api.fn.contains(t, el) -> bool", "Returns whether a table contains a given element."}
function api.fn.contains(t, el)
  for k, v in pairs(t) do
    if v == el then
      return true
    end
  end
  return false
end

api.doc.fn.indexof = {"api.fn.indexof(t, el) -> int or nil", "Returns the index of a given element in a table, or nil if not found."}
function api.fn.indexof(t, el)
  for k, v in pairs(t) do
    if v == el then
      return k
    end
  end
  return nil
end

api.doc.fn.concat = {"api.fn.concat(t1, t2)", "Adds all elements of t2 to the end of t1."}
function api.fn.concat(t1, t2)
  for i = 1, #t2 do
    t1[#t1 + 1] = t2[i]
  end
  return t1
end

api.doc.fn.mapcat = {"api.fn.mapcat(t, fn) -> t2", "Runs fn(el) for every el in t, and assuming the results are tables, combines them into a new table."}
function api.fn.mapcat(t, fn)
  local nt = {}
  for k, v in pairs(t) do
    api.fn.concat(nt, fn(v))
  end
  return nt
end

api.doc.fn.reduce = {"api.fn.reduce(t, fn) -> t2", "Runs fn(el1, el2) for every el in t, then fn(result, el3), etc, until there's only one left."}
function api.fn.reduce(t, fn)
  local len = #t
  if len == 0 then return nil end
  if len == 1 then return t[1] end

  local result = t[1]
  for i = 2, #t do
    result = fn(result, t[i])
  end
  return result
end
{'fraction_non_alphanumeric': 0.1369491525423729, 'fraction_numerical': 0.01288135593220339, 'mean_word_length': 2.66583850931677, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2425996', 'n_tokens_mistral': 1207, 'n_tokens_neox': 1180, 'n_words': 430}