Javascript:确定未知的数组长度并动态映射 [英] Javascript: Determine unknown array length and map dynamically

查看:68
本文介绍了Javascript:确定未知的数组长度并动态映射的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

尽力解释我想要做的事情。

Going to do my best at explaining what I am trying to do.

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

I have two models, mine and an api response I am receiving. When the items api response comes in, I need to map it to my model and inserts all the items. This is simple of course. Heres the issue, I need to do so without really knowing what I am dealing with. My code will be passed in two strings, one of my models mapping path and one of the api response mapping path.

以下是两个路径

var myPath = "outputModel.items[].uniqueName"
var apiPath = "items[].name"

基本上对于 apiPath中的所有项目 ,在 myPath 中按并设置为 uniqueName

Basically FOR all items in apiPath, push into items in myPath and set to uniqueName

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

What it comes down to is that my code has NO idea when two items need to be mapped, or even if they contain an array or simple field to field paths. They could even contain multiple arrays, like this:

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

******************** EXAMPLE *************************

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;

********************* ***以下是上述预期结果

************************ Here is the expected result of above

var result = {
    storeName: "",
    items: [
        {
            name: "Hammer",
            sku:"12345qwert"
        },
        {
            name: "Bike",
            sku:"asdfghhj"
        },
        {
            name: "Bike",
            sku:"zxcvbn"
        },
        {
            name: "Fork",
            sku:"0987dfgh"        }
    ]
};

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

I will be given a set of paths for EACH value to be mapped. In the case above, I was handed two sets of paths because I am mapping two values. It would have to traverse both sets of arrays to create the single array in my model.

问题 - 如何动态检测数组并正确移动数据无论什么两个模型路径看起来像?可能?

Question - How can I dynamically detect arrays and move the data around properly no matter what the two model paths look like? Possible?

推荐答案

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

As mentioned in the comments, there is no strict definition of the input format, it is hard to do it with perfect error handling and handle all corner cases.

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

Here is my lengthy implementation that works on your sample, but might fail for some other cases:

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));

这篇关于Javascript:确定未知的数组长度并动态映射的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆