package water.rapids.ast.prims.mungers; import water.fvec.Frame; import water.rapids.Env; import water.rapids.Val; import water.rapids.ast.AstParameter; import water.rapids.ast.AstRoot; import water.rapids.vals.ValFrame; import water.rapids.vals.ValRow; import water.rapids.ast.AstPrimitive; import water.rapids.ast.params.AstNum; /** * Column slice; allows python-like syntax. * Numbers past last column are allowed and ignored in NumLists, but throw an * error for single numbers. Negative numbers have the number of columns * added to them, before being checked for range. */ public class AstColPySlice extends AstPrimitive { @Override public String[] args() { return new String[]{"ary", "cols"}; } @Override public int nargs() { return 1 + 2; } // (cols_py src [col_list]) @Override public String str() { return "cols_py"; } @Override public Val apply(Env env, Env.StackHelp stk, AstRoot asts[]) { Val v = stk.track(asts[1].exec(env)); AstParameter colList = (AstParameter) asts[2]; if (v instanceof ValRow) { ValRow vv = (ValRow) v; return vv.slice(colList.columns(vv.getNames())); } Frame fr = v.getFrame(); int[] cols = colList.columns(fr.names()); Frame fr2 = new Frame(); if (cols.length == 0) // Empty inclusion list? return new ValFrame(fr2); if (cols[0] < 0) // Negative cols have number of cols added for (int i = 0; i < cols.length; i++) cols[i] += fr.numCols(); if (asts[2] instanceof AstNum && // Singletons must be in-range (cols[0] < 0 || cols[0] >= fr.numCols())) throw new IllegalArgumentException("Column must be an integer from 0 to " + (fr.numCols() - 1)); for (int col : cols) // For all included columns if (col >= 0 && col < fr.numCols()) // Ignoring out-of-range ones fr2.add(fr.names()[col], fr.vecs()[col]); return new ValFrame(fr2); } }