Skip to content

Instantly share code, notes, and snippets.

@JeffreyZhao
Last active July 17, 2019 10:47
Show Gist options
  • Save JeffreyZhao/d131293c3f7db2e552c6 to your computer and use it in GitHub Desktop.
Save JeffreyZhao/d131293c3f7db2e552c6 to your computer and use it in GitHub Desktop.

打印表头

小明正在用JavaScript写一个日志分析程序。该程序会将日志转化为CSV文件,以便在Excel等应用中加载为一个表格。现在他在生成表头上遇到了困难。

他需要实现如下一个方法:

function printLine(array) {
    console.log(array.join(","));
}

function printHeader(obj) {
	/* 使用 printLine 输出内容*/
}

输入

小明获取一个对象,需要根据这个对象的结构生成表头。例如:

{
	Process: {
		CpuUsage: 0
		VirtualMemory: 0,
		PrivateMemory: 0
	},
	Subscriptions: {
		Order: {
			TotalCount: 0,
			LastMinute: 0,
			Failed: 0
		},
		User: {
			TotalCount: 0
			LastMinute: 0
		}
	}
}

由于表头仅和对象结构相关,因此无需关注字段的值。

输出

输出为一行至多行文本,为CSV格式,字段之间以逗号隔开(简化问题起见,字段本身不包含逗号)。

如上输入,则需要得到以下输出:

Process,,,Subscriptions
CpuUsage,VirtualMemory,PrivateMemory,Order,,,User
,,,TotalCount,LastMinute,Failed,TotalCount,LastMinute

该CSV文件内容使用Excel打开便会得到以下表格(请忽略格式):

ProcessSubscriptions
CpuUsageVirtualMemoryPrivateMemoryOrderUser
TotalCountLastMinuteFailedTotalCount LastMinute

总而言之,是将对象结构转化为如上表头。

@yszou
Copy link

yszou commented Mar 23, 2016

// | root     |
// | Process  |                               | Other    | Subscriptions
// | CpuUsage | VirtualMemory | PrivateMemory | CpuUsage | Order         |            |        | User
// |                                          |          | TotalCount    | LastMinute | Failed | TotalCount | What |    | LastMinute |
// |                                          |          |                                     |            | AA   | BB |

var data = {
    Process: {
        CpuUsage: 0,
        VirtualMemory: 0,
        PrivateMemory: 0
    },

    Other: {
        CpuUsage: 0,
    },

    Subscriptions: {
        Order: {
            TotalCount: 0,
            LastMinute: 0,
            Failed: 0
        },
        User: {
            TotalCount: 0,
            What: {
              AA: 0,
              BB: 0
            },
            LastMinute: 0
        }
    }
};

// 原始结构就是树
// 表格的高, depth, 深度
// 表格的宽, breadth, 广度 -> 不是树的广度, What 会被子节点撑开, 应该是延续之前一个节点的"列位"
// 遍历过程中可以得到 lv 和 column , 那就可以直接刚坐标了
// 列表尾部的 undefined 不会保留, 但是遍历过程中又是不知道最大广度的, 最后填坑吧

function findMax(data){
  var group = {}; // breadth, depth
  var result = [];

  function dig(obj, info, key, lv, column){

    //console.log(key, lv - 1 - 1, info['breadth'] + column - 1 - 1);
    if(!result[lv - 1 - 1]){result[lv - 1 - 1] = []};
    result[lv - 1 - 1][info['breadth'] + column - 1 - 1] = key;

    if (Object.prototype.toString.call(obj) !== '[object Object]'){ return }


    if( lv > info['depth']){ info['depth'] = lv }
    if( column > info['breadth']){ info['breadth'] = column }

    var count = -1;
    for(var k in obj){
      count += 1;
      dig(obj[k], info, k, lv+1, column + count);
    }
    info['breadth'] += count;
  }

  for(var k in data){
    group[k] = {breadth: 1, depth: 1};
    dig(data[k], group[k], k, 2, 1);
  }

  return [group, result];

}

function printHeader(obj, isPrint){
  var p = findMax({root: obj});
  var info = p[0]['root'];
  var data = p[1];
  var canvas = [];

  for(var i = 1, l = info['depth']; i < l; i++){
    canvas[i] = [];
    for(var j = 0, ll = info['breadth']; j < ll; j++){
      var cell = data[i][j] || '';
      if(cell.length < 15 && isPrint){ cell += (Array(15 - cell.length + 1).join(' '))}
      canvas[i][j] = cell;
    }
  }

  canvas.forEach(function(row){
    if(isPrint){
      console.log(row.join(' | '));
    } else {
      console.log(row.join(','));
    }
  });
}

printHeader(data, false);

@wdanxna
Copy link

wdanxna commented Mar 23, 2016

function printLine(array) {
    console.log(array.join(","));
}

function printHeader(obj) {
    function iter(obj, head, lines, line, padding) {
        if (head) {
            if (line > 0) {
                if (!lines[line - 1]) {
                    //previous line not exist.
                    var curline = [];
                    for (var i = 0; i < padding; i++) {
                        curline.push("");
                    }
                    curline.push(head);
                    lines.push(curline);
                } else {
                    // previous line exist.
                    var curline = lines[line - 1];
                    var residual = padding - lines[line - 1].length;
                    if (residual > 0) {
                        for (var i = 0; i < residual; i++) {
                            curline.push("");
                        }
                    }
                    curline.push(head);
                }
            }
        }
        if (typeof obj !== 'object') {
            return 1;
        }
        var curPadding = 0;
        for (var section in obj) {
            var p = iter(obj[section], section, lines, line + 1, padding + curPadding);
            curPadding += p;
        }
        return curPadding;
    }

    var lines = []
    iter(obj, "", lines, 0, 0);

    lines.forEach(printLine);
}

@LuoYY
Copy link

LuoYY commented Mar 23, 2016

function printLine(array){
    console.log(array.join(','));
}

function printHeader(obj) {
    var str = []; //string container
    objectPropTraversal(obj, str, 0, 0);
    for (var i in str){
        printLine(str[i]);
    }
}

function objectPropTraversal(obj, str, row, col) {
    if (typeof str[row] == 'undefined') {
        str[row] = [];
    }
    for(var value in obj){
        str[row][col] = value;
        if (typeof obj[value] == 'object') {
            col = objectPropTraversal(obj[value], str, row+1, col);
        }else{
            col++;
        }
    }
    return col;
}

@huaxinjiayou
Copy link

function printLine(array) {
    console.log(array.join(","));
}

function printHeader(obj) {
    // 根据 key 的深度展开对象,同时获取 deep 和 key 的哈希表
    // demo 结果为
    // ["0", "00", "01", "02", "1", "10", "100", "101", "102", "11", "110", "111"]
    // {0: "Process", 1: "Subscriptions", 10: "Order", 11: "User", 100: "TotalCount", 101: "LastMinute", 102: "Failed", 110: "TotalCount", 111: "LastMinute", 00: "CpuUsage", 01: "VirtualMemory", 02: "PrivateMemory"}
    var aOrder = [];
    var oOrder = {};
    fExpand(obj, '', aOrder, oOrder);

    // 最后一行输出的长度及具体信息
    // demo 结果
    // ["00", "01", "02", "100", "101", "102", "110", "111"]
    // 可以知道最长的一行长度 aRule.length
    var aRule = [];
    var sLast;
    aOrder.forEach(function (sItem, nIndex) {
        if (nIndex > 0 && sItem.indexOf(sLast) === 0) {
            aRule.pop();
        }
        aRule.push(sItem);
        sLast = sItem;
    });

    // 从 deep 为 1 开始遍历 aRule,然后逐行打印
    var nDeep = 1;
    while (true) {
        var aResult = [];
        var sLast = '';
        var nLastIndex = -1;
        aRule.forEach(function (sItem, nIndex) {
            var nLength = sItem.length;
            if (nLength < nDeep) {
                aResult.push('');
            } else if (nLength === nDeep) {
                aResult.push(oOrder[sItem]);
                nLastIndex = nIndex;
            } else {
                sItem = sItem.substr(0, nDeep);
                if (sItem !== sLast) {
                    sLast = sItem;
                    aResult.push(oOrder[sItem]);
                    nLastIndex = nIndex;
                } else {
                    aResult.push('');
                }
            }
        });

        // 去掉多余的空格
        aResult.length = nLastIndex + 1;
        if (aResult.length === 0) {
            break;
        }

        printLine(aResult);
        nDeep++;
    }
}


function fExpand(obj, sDeep, aOrder, oOrder) {
    var nIndex = 0;
    for (var sKey in obj) {
        var oVal = obj[sKey];
        var sOrder = sDeep + nIndex;
        aOrder.push(sOrder);
        oOrder[sOrder] = sKey;
        if (fIsObj(oVal)) {
            fExpand(oVal, sOrder, aOrder, oOrder);
        }
        nIndex++;
    }
}

function fIsObj(obj) {
    return Object.prototype.toString.call(obj) === '[object Object]';
}

@bao-qian
Copy link

js 版本,基本跟上面的 python 版本一样。

function printLine(array) {
    console.log(array.join(","));
}

function printHeader(obj) {
    var table = [];
    var width = 0;

    function create_table(header, height) {
        for (var key in header) {
            var line = table[height] || [];
            var n = width - line.length;
            line.push.apply(line, new Array(n).fill(''));
            line.push(key);

            if (typeof header[key] == "object") {
                create_table(header[key], height + 1)
            }
            width = Math.max(line.length, width);
            table[height] = line
        }
    }

    create_table(obj, 0);
    table.forEach(printLine);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment