#!/usr/bin/env python3
""" reduce.py - process a stream, and find the min, max, sum or whatever else """

import sys
from math import inf, sqrt
from pathlib import Path

def num(s):
	try:
		return int(s)
	except ValueError:
		return float(s)

def num_or_str(s):
	try:
		return int(s)
	except ValueError:
		pass
	try:
		return float(s)
	except ValueError:
		pass
	return s

def reduce(istream, fn, acc=None, strip=True, numbers=True):
	if acc is None:
		acc = next(istream)
	for s in istream:
		if strip:
			s = s.strip()
		v = s
		if numbers:
			v = num_or_str(v)
		try:
			acc = fn(acc, v)
		except TypeError:
			if acc in (inf, -inf):
				acc = v
			else:
				acc = fn(str(acc), s)
	return acc

fn_min = min
fn_max = max

def min(istream):
	return reduce(istream, fn_min, inf)

def max(istream):
	return reduce(istream, fn_max, -inf)

def sum(istream):
	return reduce(istream, lambda acc,v: acc+v, 0)

def mean(istream):
	n, tot = reduce(istream, lambda acc,v: (acc[0]+1, acc[1]+v), (0,0))
	return tot/n

def hypot(istream):
	tot_sq = reduce(istream, lambda acc,v: acc+v*v, 0)
	return sqrt(tot_sq)

def rms(istream):
	n, tot_sq = reduce(istream, lambda acc,v: (acc[0]+1, acc[1]+v**2), (0,0))
	return sqrt(tot_sq/n)

def sd_sample(istream):
	n, tot, tot_sq = reduce(istream, lambda acc,v: (acc[0]+1, acc[1]+v, acc[2]+v**2), (0,0,0))
	return sqrt((n * tot_sq - tot ** 2) / (n * (n - 1)))

def sd(istream):
	n, tot, tot_sq = reduce(istream, lambda acc,v: (acc[0]+1, acc[1]+v, acc[2]+v**2), (0,0,0))
	return sqrt((n * tot_sq - tot ** 2) / (n ** 2))

def main():
	prog = Path(sys.argv[0])
	name = prog.stem
	if name == "reduce" and len(sys.argv) > 1:
		name = sys.argv[1]
	if name == "min":
		print(min(sys.stdin))
	elif name == "max":
		print(max(sys.stdin))
	elif name == "sum":
		print(sum(sys.stdin))
	elif name == "mean":
		print(mean(sys.stdin))
	elif name == "hypot":
		print(hypot(sys.stdin))
	elif name == "rms":
		print(rms(sys.stdin))
	elif name == "sd":
		print(sd(sys.stdin))
	elif name == "sd_sample":
		print(sd_sample(sys.stdin))
	else:
		print(f"Usage: {prog.name} (min|max|sum|mean|hypot|rms|sd|sd_sample)", file=sys.stderr)
		sys.exit(1)

if __name__ == "__main__":
	main()
