Javascript:确定未知的数组长度并动态映射

Rob*_*Rob 10 javascript arrays string json object

我会尽力解释我想要做的事情.

我有两个模型,我和我收到的api响应.当项目api响应进来时,我需要将其映射到我的模型并插入所有项目.这当然很简单.这是问题所在,我需要在不知道自己在做什么的情况下这样做.我的代码将以两个字符串传递,一个是我的模型映射路径和一个api响应映射路径.

这是两条路

var myPath = "outputModel.items[].uniqueName"
var apiPath = "items[].name"
Run Code Online (Sandbox Code Playgroud)

基本上是所有itemsapiPath,推到itemsmyPath与设置uniqueName

它归结为我的代码不知道何时需要映射两个项目,或者即使它们包含数组或简单字段到字段路径.它们甚至可以包含多个数组,如下所示:

********************示例*************************

var items = [
    {
        name: "Hammer",
        skus:[
            {num:"12345qwert"}
        ]
    },
    {
        name: "Bike",
        skus:[
            {num:"asdfghhj"},
            {num:"zxcvbn"}
        ]
    },
    {
        name: "Fork",
        skus:[
            {num:"0987dfgh"}
        ]
    }
]

var outputModel = {
    storeName: "",
    items: [
        {
            name: "",
            sku:""
        }
    ]
};


outputModel.items[].name = items[].name;
outputModel.items[].sku = items[].skus[].num;
Run Code Online (Sandbox Code Playgroud)

************************这是上面的预期结果

var result = {
    storeName: "",
    items: [
        {
            name: "Hammer",
            sku:"12345qwert"
        },
        {
            name: "Bike",
            sku:"asdfghhj"
        },
        {
            name: "Bike",
            sku:"zxcvbn"
        },
        {
            name: "Fork",
            sku:"0987dfgh"        }
    ]
};
Run Code Online (Sandbox Code Playgroud)

我将获得一组用于映射EACH值的路径.在上面的例子中,我被传递了两组路径,因为我正在映射两个值.它必须遍历两组数组才能在我的模型中创建单个数组.

问题 - 无论两个模型路径如何,我如何动态检测数组并正确移动数据?可能?

Tie*_*Ren 0

正如评论中提到的,输入格式没有严格的定义,很难做到完美的错误处理并处理所有极端情况。

这是我的冗长的实现,适用于您的示例,但在其他情况下可能会失败:

function merge_objects(a, b) {
    var c = {}, attr;
    for (attr in a) { c[attr] = a[attr]; }
    for (attr in b) { c[attr] = b[attr]; }
    return c;
}


var id = {
    inner: null,
    name: "id",
    repr: "id",
    type: "map",
    exec: function (input) { return input; }
};

// set output field
function f(outp, mapper) {
    mapper = typeof mapper !== "undefined" ? mapper : id;
    var repr = "f("+outp+","+mapper.repr+")";
    var name = "f("+outp;
    return {
        inner: mapper,
        name: name,
        repr: repr,
        type: "map",
        clone: function(mapper) { return f(outp, mapper); },
        exec:
        function (input) {
            var out = {};
            out[outp] = mapper.exec(input);
            return out;
        }
    };
}

// set input field
function p(inp, mapper) {
    var repr = "p("+inp+","+mapper.repr+")";
    var name = "p("+inp;
    return {
        inner: mapper,
        name: name,
        repr: repr,
        type: mapper.type,
        clone: function(mapper) { return p(inp, mapper); },
        exec: function (input) {
            return mapper.exec(input[inp]);
        }
    };
}

// process array
function arr(mapper) {
    var repr = "arr("+mapper.repr+")";
    return {
        inner: mapper,
        name: "arr",
        repr: repr,
        type: mapper.type,
        clone: function(mapper) { return arr(mapper); },
        exec: function (input) {
            var out = [];
            for (var i=0; i<input.length; i++) {
                out.push(mapper.exec(input[i]));
            }
            return out;
        }
    };
}

function combine(m1, m2) {
    var type = (m1.type == "flatmap" || m2.type == "flatmap") ? "flatmap" : "map";
    var repr = "combine("+m1.repr+","+m2.repr+")";
    return {
        inner: null,
        repr: repr,
        type: type,
        name: "combine",
        exec:
        function (input) {
            var out1 = m1.exec(input);
            var out2 = m2.exec(input);
            var out, i, j;


            if (m1.type == "flatmap" && m2.type == "flatmap") {
                out = [];
                for (i=0; i<out1.length; i++) {
                    for (j=0; j<out2.length; j++) {
                        out.push(merge_objects(out1[i], out2[j]));
                    }
                }
                return out;
            }

            if (m1.type == "flatmap" && m2.type != "flatmap") {
                out = [];
                for (i=0; i<out1.length; i++) {
                    out.push(merge_objects(out1[i], out2));
                }
                return out;
            }

            if (m1.type != "flatmap" && m2.type == "flatmap") {
                out = [];
                for (i=0; i<out2.length; i++) {
                    out.push(merge_objects(out2[i], out1));
                }
                return out;
            }

            return merge_objects(out1, out2);
        }
    };
}

function flatmap(mapper) {
    var repr = "flatmap("+mapper.repr+")";
    return {
        inner: mapper,
        repr: repr,
        type: "flatmap",
        name: "flatmap",
        clone: function(mapper) { return flatmap(mapper); },
        exec:
        function (input) {
            var out = [];
            for (var i=0; i<input.length; i++) {
                out.push(mapper.exec(input[i]));
            }
            return out;
        }
    };
}



function split(s, t) {
    var i = s.indexOf(t);

    if (i == -1) return null;
    else {
        return [s.slice(0, i), s.slice(i+2, s.length)];
    }
}

function compile_one(inr, outr) {
    inr = (inr.charAt(0) == ".") ? inr.slice(1, inr.length) : inr;
    outr = (outr.charAt(0) == ".") ? outr.slice(1, outr.length) : outr;

    var box = split(inr, "[]");
    var box2 = split(outr, "[]");
    var m, ps, fs, i, j;

    if (box == null && box2 == null) { // no array!
        m = id;

        ps = inr.split(".");
        fs = outr.split(".");

        for (i=0; i<fs.length; i++) { m = f(fs[i], m); }
        for (j=0; j<ps.length; j++) { m = p(ps[j], m); }

        return m;
    }

    if (box != null && box2 != null) { // array on both sides
        m = arr(compile_one(box[1], box2[1]));

        ps = box[0].split(".");
        fs = box[0].split(".");

        for (i=0; i<fs.length; i++) { m = f(fs[i], m); }
        for (j=0; j<ps.length; j++) { m = p(ps[j], m); }

        return m;
    }

    if (box != null && box2 == null) { // flatmap
        m = flatmap(compile_one(box[1], outr));

        ps = box[0].split(".");

        for (j=0; j<ps.length; j++) { m = p(ps[j], m); }

        return m;
    }

    return null;
}

function merge_rules(m1, m2) {
    if (m1 == null) return m2;
    if (m2 == null) return m1;

    if (m1.name == m2.name && m1.inner != null) {
        return m1.clone(merge_rules(m1.inner, m2.inner));
    } else {
        return combine(m1, m2);
    }

}

var input = {
    store: "myStore",
    items: [
        {name: "Hammer", skus:[{num:"12345qwert"}]},
        {name: "Bike", skus:[{num:"asdfghhj"}, {num:"zxcvbn"}]},
        {name: "Fork", skus:[{num:"0987dfgh"}]}
    ]
};

var m1 = compile_one("items[].name", "items[].name");
var m2 = compile_one("items[].skus[].num", "items[].sku");
var m3 = compile_one("store", "storeName");
var m4 = merge_rules(m3,merge_rules(m1, m2));
var out = m4.exec(input);


alert(JSON.stringify(out));
Run Code Online (Sandbox Code Playgroud)