use std::iter::{Product, Sum, Zip};
use std::ops::{Rem, Neg, Add, Sub, Div, Mul};
use std::hash::Hash;
use std::cmp::Ordering;
pub fn map<T,U>(f: impl Fn(T) -> U, it: impl Iterator<Item=T>) -> impl Iterator<Item=U> {
it.map(f)
}
pub fn sum<T: Sum>(it: impl Iterator<Item=T>) -> T {
it.sum()
}
pub fn foldl<T,R>(init: R, f: impl Fn(R,T) -> R, it: impl DoubleEndedIterator<Item=T>) -> R {
it.fold(init, f)
}
pub fn foldr<T,R>(init: R, f: impl Fn(R,T) -> R, it: impl DoubleEndedIterator<Item=T>) -> R {
it.rev().fold(init, f)
}
pub fn filter<T>(f: impl Fn(&T) -> bool, it: impl Iterator<Item=T>) -> impl Iterator<Item=T> {
it.filter(f)
}
pub fn filter_not<T>(f: impl Fn(&T) -> bool, it: impl Iterator<Item=T>) -> impl Iterator<Item=T> {
it.filter(move |x| !f(x))
}
pub fn head<T>(mut it: impl Iterator<Item=T>) -> Option<T> {
it.next()
}
pub fn tail<T>(mut it: impl Iterator<Item=T>) -> Option<Vec<T>> {
if let Some(_) = it.next() {
let mut ret = Vec::new();
ret.extend(it);
return Some(ret);
}
None
}
pub fn last<T>(it: impl Iterator<Item=T>) -> Option<T> {
let mut ret = None;
for i in it {
ret = Some(i);
}
ret
}
pub fn init<T>(it: impl Iterator<Item=T>) -> Option<Vec<T>> {
let mut ret = Vec::new();
ret.extend(it);
let size = ret.len();
if size == 0 {
return None;
}
ret.remove(size-1);
Some(ret)
}
pub fn skip<T>(n: usize, mut it: impl Iterator<Item=T>) -> Vec<T> {
for _ in 0..n {
it.next();
}
let mut ret = Vec::new();
ret.extend(it);
ret
}
pub fn take<T>(n: usize, mut it: impl Iterator<Item=T>) -> Vec<T> {
let mut ret = Vec::new();
for _ in 0..n {
match it.next() {
None => break,
Some(item) => ret.push(item)
}
}
ret
}
pub fn product<T: Product>(it: impl Iterator<Item=T>) -> T {
it.product()
}
pub fn length<T>(it: impl Iterator<Item=T>) -> usize {
it.count()
}
pub fn reverse<T>(it: impl Iterator<Item=T>) -> Vec<T> {
let mut ret = Vec::new();
ret.extend(it);
ret.reverse();
ret
}
pub fn concat<T>(it1: impl Iterator<Item=T>, it2: impl Iterator<Item=T>) -> Vec<T> {
let mut ret = Vec::new();
ret.extend(it1);
ret.extend(it2);
ret
}
pub fn id<T>(x: T) -> T {
x
}
pub fn min<T: Ord>(it: impl Iterator<Item=T>) -> Option<T> {
it.min()
}
pub fn max<T: Ord>(it: impl Iterator<Item=T>) -> Option<T> {
it.max()
}
pub fn neg<U,T: Neg<Output=U>>(x: T) -> U {
x.neg()
}
pub fn rem<T>(x: T, y: T) -> T
where T: Rem<Output=T>
{
x.rem(y)
}
pub fn add<T: Add<Output=T>>(x: T, y: T) -> T {
x + y
}
pub fn sub<T: Sub<Output=T>>(x: T, y: T) -> T {
x - y
}
pub fn mul<T: Mul<Output=T>>(x: T, y: T) -> T {
x * y
}
pub fn div<T: Div<Output=T>>(x: T, y: T) -> T {
x / y
}
pub fn find<K:Hash+Eq,V>(key: K, mut it: impl Iterator<Item=(K,V)>) -> Option<(K,V)> {
it.find(move |(x,_)| *x == key)
}
pub fn sorted<T: Ord>(it: impl Iterator<Item=T>) -> impl Iterator<Item=T> {
let mut tmp = Vec::new();
tmp.extend(it);
tmp.sort_unstable();
tmp.into_iter()
}
pub fn sorted_by<T>(f: impl Fn(&T,&T) -> Ordering, it: impl Iterator<Item=T>) -> impl Iterator<Item=T> {
let mut tmp = Vec::new();
tmp.extend(it);
tmp.sort_unstable_by(f);
tmp.into_iter()
}
pub fn zip<T,U>(it1: impl Iterator<Item=T>, it2: impl Iterator<Item=U>) -> Zip<impl Iterator<Item=T>, impl Iterator<Item=U>> {
let mut ret1 = Vec::new();
ret1.extend(it1);
let mut ret2 = Vec::new();
ret2.extend(it2);
ret1.into_iter().zip(ret2.into_iter())
}
pub fn zip_with<T,U,V>(f: impl Fn((T,U)) -> V, it1: impl Iterator<Item=T>, it2: impl Iterator<Item=U>) -> impl Iterator<Item=V> {
zip(it1,it2).map(f)
}