代码之家  ›  专栏  ›  技术社区  ›  Stefan Steiger Marco van de Voort

如何以低开销访问两个数组作为javascript中的关联数组?

  •  0
  • Stefan Steiger Marco van de Voort  · 技术社区  · 7 年前

    通过Ajax返回表时,可以分别使用列名和行值,如下所示:

    let columns = ["col1", "col2", "col3"];
    let rows = [
          ["row 1 col 1", "row 1 col 2", "row 1 col 3"]
        , ["row 2 col 1", "row 2 col 2", "row 2 col 3"]
        , ["row 3 col 1", "row 3 col 2", "row 3 col 3"]
        , ["row 4 col 1", "row 4 col 2", "row 4 col 3"]
        , ["row 5 col 1", "row 5 col 2", "row 5 col 3"]
    ];
    

    或者像这样的关联数组

    let rows = [
          { "col1": "row 1 col 1", "col2": "row 1 col 2", "col3": "row 1 col 3" }
        , { "col1": "row 2 col 1", "col2": "row 2 col 2", "col3": "row 2 col 3" }
        , { "col1": "row 3 col 1", "col2": "row 3 col 2", "col3": "row 3 col 3" }
        , { "col1": "row 4 col 1", "col2": "row 4 col 2", "col3": "row 4 col 3" }
        , { "col1": "row 5 col 1", "col2": "row 5 col 2", "col3": "row 5 col 3" }
    ];
    

    现在,如果有很多数据,第一个变量将导致传输的数据更少。

    问题是,我不能像行[i][“col1]那样访问它,因为我可以使用第二个变量。

    现在,我可以只获取行和列,然后从中创建一个关联数组,比如

    let columns = ["col1", "col2", "col3"];
    
    let data = [
          ["row 1 col 1", "row 1 col 2", "row 1 col 3"]
        , ["row 2 col 1", "row 2 col 2", "row 2 col 3"]
        , ["row 3 col 1", "row 3 col 2", "row 3 col 3"]
        , ["row 4 col 1", "row 4 col 2", "row 4 col 3"]
        , ["row 5 col 1", "row 5 col 2", "row 5 col 3"]
    ];
    
    
    
    let arr = [];
    
    
    for (let j = 0; j < data.length; ++j)
    {
        let obj = {}; // "associative array" or Object
    
        for (let i = 0; i < columns.length; ++i)
        {
            obj[columns[i]] = data[j][i];
        }
        arr.push(obj);
    }
    

    但是我必须复制对象,如果行数和列数很大,这可能需要时间和内存。

    有没有什么好的(非时间和非内存消耗)方法可以在JavaScript中实现这一点?

    我需要的是索引属性,但它们似乎不存在于javascript中…

    我最近得到的是代理对象:

    let columns = ["col1", "col2", "col3"];
    let rows = [
          ["row 1 col 1", "row 1 col 2", "row 1 col 3"]
        , ["row 2 col 1", "row 2 col 2", "row 2 col 3"]
        , ["row 3 col 1", "row 3 col 2", "row 3 col 3"]
        , ["row 4 col 1", "row 4 col 2", "row 4 col 3"]
        , ["row 5 col 1", "row 5 col 2", "row 5 col 3"]
    ];
    
    let cols = {}; // "associative array" or Object
    
    for (let i = 0; i < columns.length; ++i)
    {
        cols[columns[i]] = i;
    }
    
    
    let handler2 = {
        get: function (obj, prop, receiver)
        {
            return obj[cols[prop]];
        }
    };
    
    // https://www.sitepoint.com/es6-proxies/
    let handler = {
        get: function (obj, prop, receiver)
        {
            console.log("obj:", obj, "prop:", prop, "receiver :", receiver);
            //return obj[prop];
            //return obj[cols[prop]];
            return new Proxy(obj[prop], handler2);
        }
    
        , set: function (obj, key, value)
        {
            console.log(obj, key, value);
        }
    
    };
    
    let p = new Proxy(rows, handler);
    

    这里的问题是——除了IE11不支持代理之外——我需要在每行访问上创建一个新的代理,因为它看起来不支持对象数组……

    在一个 良好/性能良好 怎么样?

    我最不想写的就是这样的代码:

    let columns = ["col1", "col2", "col3"];
    let rows = [
          ["row 1 col 1", "row 1 col 2", "row 1 col 3"]
        , ["row 2 col 1", "row 2 col 2", "row 2 col 3"]
        , ["row 3 col 1", "row 3 col 2", "row 3 col 3"]
        , ["row 4 col 1", "row 4 col 2", "row 4 col 3"]
        , ["row 5 col 1", "row 5 col 2", "row 5 col 3"]
    ];
    
    let cols = {}; // "associative array" or Object
    
    for (let i = 0; i < columns.length; ++i)
    {
        cols[columns[i]] = i;
    }
    
    let index_col1 = cols["col1"];
    let index_col2 = cols["col2"];
    let index_col3 = cols["col3"];
    
    
    for (var i = 0; i < rows.length; ++i)
    {
        console.log("col1:", rows[i][index_col1], "col2:", rows[i][index_col2], "col3:", rows[i][index_col3]);
    }
    

    这就是我现在要做的…

    2 回复  |  直到 7 年前
        1
  •  0
  •   Nicolas Gehlert    7 年前

    let rows = [
          ["col1", "col2", "col3"],
          ["row 1 col 1", "row 1 col 2", "row 1 col 3"],
          ["row 2 col 1", "row 2 col 2", "row 2 col 3"],
          ["row 3 col 1", "row 3 col 2", "row 3 col 3"],
          ["row 4 col 1", "row 4 col 2", "row 4 col 3"],
          ["row 5 col 1", "row 5 col 2", "row 5 col 3"]
    ];
    

    let table = {
        "col1": ["row 1 col 1", "row 2 col 1", ..."],
        "col2": ["row 1 col 2", "row 2 col 2", ..."]
    }
    

    在这种方法中,很容易(也很快)获得行条目的数据。表['col1'][索引]

        2
  •  0
  •   Stefan Steiger Marco van de Voort    7 年前


    interface IProxyHandler
    {
        get(obj, prop, receiver);
    }
    
    
    declare class Proxy
    {
        public constructor(obj, handler_callback: IProxyHandler);
    }
    
    interface SomeTable
    {
        col1: string;
        col2: number;
        col3: Date;
    }
    
    export class table<T>
    {
    
        public obj: T[];
        //public columns: map<string, number>;
        public columns: { [key: string]: number };
    
        protected i: number;
        protected accessor: Proxy;
    
    
        //get bar(): boolean
        //{
        //    return null; // this._bar;
        //}
        //set bar(theBar: boolean)
        //{
        //    //this._bar = theBar;
        //}
    
        public row(index:number): T
        {
            this.i = index;
            return <T><any>this.accessor;
        }
    
        public rows :T[];
    
        constructor(rows: any[][], columnNames:string[])
        {
            this.obj = <any>rows;
            this.i = 0;
    
            // this.columns = columnNames;
            this.columns = {}; // "associative array" or Object
    
            for (let i = 0; i < columnNames.length; ++i)
            {
                this.columns[columnNames[i]] = i;
            }
    
    
            let handler: IProxyHandler = {
                get: function (obj, prop, receiver)
                {
                    return this.obj[this.i][this.columns[prop]];
                }
            };
    
            handler.get = handler.get.bind(this);
            this.row = this.row.bind(this);
            this.accessor = new Proxy(this.obj, handler);
    
            let handler2: IProxyHandler = {
                get: function (obj, prop, receiver)
                {
                    return this.row(prop);
                }
            };
            handler2.get = handler2.get.bind(this);
    
            this.rows = <any> new Proxy(this.obj, handler2);
        }
    
    
    }
    
    
    // https://caniuse.com/#feat=proxy
    // Sorry, your browser is no longer supported. 
    // If you want this program to support IE11, develop a proxy-polyfill for IE11. 
    // Hint from Babel-docs: ES2015-Proxies requires support on the engine level; 
    // it is thus not possible to polyfill Proxy in ES5.
    export function testTable()
    {
        let columns = ["col1", "col2", "col3"];
        let rows = [
            ["row 1 col 1", "row 1 col 2", "row 1 col 3"]
            , ["row 2 col 1", "row 2 col 2", "row 2 col 3"]
            , ["row 3 col 1", "row 3 col 2", "row 3 col 3"]
            , ["row 4 col 1", "row 4 col 2", "row 4 col 3"]
            , ["row 5 col 1", "row 5 col 2", "row 5 col 3"]
        ];
    
        let x = new table<SomeTable>(rows, columns);
    
        console.log(x.rows[0].col1);
        // console.log(x.row(1).col1);
        // console.log(x.obj[0][0]);
    }
    


    如果我要使用函数,我需要这样做:

    public rowz(index: number, colName: string): any
    {
        this.i = index;
        return this.obj[index][this.columns[colName]];
    }
    

    public rowz(index: number): any
    {
        this.i = index;
    
        return function (colName)
        {
            this.obj[index][this.columns[colName]];
        };
    
    }
    


    interface ITestTable1
    {
        col1:number;
        col2:number;
    }
    
    
    interface ITestTable2
    {
        a:number;
        b:number;
        c:number;
    }
    
    
    
    export class TableWrapper<T>
    {
        public rows:any[][];
        protected m_accessor:object;
        protected m_i:number;
    
        protected m_columnMap: { [columnName: string]: number; };
        protected m_columns: string[];
        protected m_columnLength:number;
    
    
        public get rowCount(): number
        {
            return this.rows.length;
        }
    
    
        public get columnCount(): number
        {
            return this.m_columns.length;
        }
    
    
        get columns(): string[]
        {
            return this.m_columns;
        }
    
    
        protected setColumns(cols: string[])
        {
            this.m_columnLength = cols.length;
    
            this.m_columnMap = null;
            this.m_columnMap = {};
    
            for (let i = 0; i < this.m_columnLength; ++i)
            {
                this.m_columnMap[cols[i]] = i;
            }
    
            this.m_columns = cols;
        } // End Sub setColumns 
    
    
        public row(i:number):T
        {
            this.m_i = i;
            return <T><any>this.m_accessor;
        }
    
    
        public getIndex(name:string):number
        {
            return this.m_columnMap[name];
        }
    
    
        public addRow(dat:any[])
        {
            this.rows.push(dat);
            return this;
        }
    
    
        public removeRow(i:number)
        {
            this.rows.splice(i, 1);
            return this;
        }
    
    
        constructor(columns: string[], data: Array<any[]>, ignoreCase?:boolean)
        {
            if (ignoreCase == null)
                ignoreCase = true;
    
            for (let i = 0; i< columns.length; ++i)
            {
                columns[i] = columns[i].toLowerCase();
            } // Next i 
    
    
            let that = this;
            this.getIndex.bind(this);
            this.setColumns.bind(this);
            this.row.bind(this);
            this.addRow.bind(this);
            this.removeRow.bind(this);
    
            this.rows = data;
            this.setColumns(columns);
            this.m_accessor = { }; // Creates a new object
    
    
            for (let i = 0; i < columns.length; ++i)
            {
                let propName = columns[i];
    
                Object.defineProperty(this.m_accessor, propName, {
                    // Using shorthand method names (ES2015 feature). 
                    // get() { return bValue;}, 
                    // set(value) { bValue = value;}, 
                    // This is equivalent to: 
                    // get: function() { return bValue; }, 
                    // set: function(value) { bValue = value; }, 
                    // And could be written as (getter = getter.bind(this)) 
                    // get: getter, 
                    // set: setter, 
                    get: function ()
                    { 
                        let currentRow =  <any> that.rows[that.m_i];
                        return currentRow == null ? currentRow : currentRow[i]; 
                    },
                    set: function(value:any) 
                    { 
                        let currentRow =  <any> that.rows[that.m_i];
                        if (currentRow!= null )
                            currentRow[i] = value; 
                    },
                    enumerable: true,
                    configurable: true
                });
            } // Next i 
    
        }
    
    }
    
    
    let tab: TableWrapper<ITestTable1> = new TableWrapper<ITestTable1>(["col1","col2"], [[1,2], [3,4]]);
    // tab.columns=["col1","col2", "col3"];
    
    let hi :TableWrapper<ITestTable2>= new TableWrapper<ITestTable2>(["a","b","c"], [[1,2,3],[4,5,6] ]);
    
    
    console.log(tab.row(0).col1);
    console.log(hi.row(0).a);
    console.log(hi.row(1).b);
    console.log(hi.row(0).c);
    
    hi.row(0).a = 123;
    
    
    for (let i = 0; i< hi.rowCount; ++i)
    {
        for (let j=0; j < hi.columnCount; ++j)
        {
            console.log(hi.rows[i][j]);
    
            console.log(hi.row(i).a);
            console.log(hi.row(i).b);
            console.log(hi.row(i).c);
    
            console.log((<any>hi.row(i))[hi.columns[j]]);
            console.log((<any>hi.row(i))[hi.columns[j]]);
            console.log((<any>hi.row(i))[hi.columns[j]]);
        }
    
    }