arrLookupByMaxmin.mjs

import get from 'lodash-es/get.js'
import each from 'lodash-es/each.js'
import isNumber from 'lodash-es/isNumber.js'
import cloneDeep from 'lodash-es/cloneDeep.js'
import isearr from './isearr.mjs'
import isestr from './isestr.mjs'
import isnum from './isnum.mjs'
import iseobj from './iseobj.mjs'
import isfun from './isfun.mjs'
import cdbl from './cdbl.mjs'
import haskey from './haskey.mjs'


/**
 * 依照指定最大最小值物件陣列,查找陣列內各元素之所屬值
 *
 * Unit Test: {@link https://github.com/yuda-lyu/wsemi/blob/master/test/arrLookupByMaxmin.test.mjs Github}
 * @memberOf wsemi
 * @param {Array} arr 輸入要被切割的陣列,需為物件陣列,否則無法添加查找結果
 * @param {Array} maxmins 輸入要切分的最大最小值物件陣列,每個元素需為物件,至少得要包含keyMax與keyMin欄位
 * @param {Object} [opt={}] 輸入設定物件
 * @param {String} [opt.keyMax='max'] 輸入maxmins內各元素中,儲存最大值欄位字串,預設'max'
 * @param {String} [opt.keyMin='min'] 輸入maxmins內各元素中,儲存最小值欄位字串,預設'min'
 * @param {String} [opt.keyValue='value'] 輸入arr內各元素中,若為物件,則儲存欲判斷數值之欄位字串,預設'value'
 * @param {String} [opt.keyItems='items'] 輸入回傳arr物件陣列中,儲存所屬maxmins元素之欄位字串,預設'items'
 * @param {Function} [opt.beforeAddResult=null] 輸入儲存至arr物件陣列前的處理函數,預設null
 * @returns {Array} 回傳切割後的陣列
 * @example
 *
 * let arr1 = [
 *     {
 *         name: 'a',
 *         value: 1.1,
 *     },
 *     {
 *         name: 'b',
 *         value: 2.2,
 *     },
 *     {
 *         name: 'c',
 *         value: 3.3,
 *     },
 *     {
 *         name: 'd',
 *         value: 4.4,
 *     },
 *     {
 *         name: 'e',
 *         value: 5.5,
 *     },
 *     {
 *         name: 'f',
 *         value: 6.6,
 *     },
 * ]
 * let mm1 = [
 *     {
 *         min: 0,
 *         max: 2,
 *     },
 *     {
 *         min: 2,
 *         max: 5,
 *     },
 * ]
 * console.log(JSON.stringify(arrLookupByMaxmin(arr1, mm1), null, 2))
 * // => [
 * //   {
 * //     "name": "a",
 * //     "value": 1.1,
 * //     "items": [
 * //       {
 * //         "min": 0,
 * //         "max": 2
 * //       }
 * //     ]
 * //   },
 * //   {
 * //     "name": "b",
 * //     "value": 2.2,
 * //     "items": [
 * //       {
 * //         "min": 2,
 * //         "max": 5
 * //       }
 * //     ]
 * //   },
 * //   {
 * //     "name": "c",
 * //     "value": 3.3,
 * //     "items": [
 * //       {
 * //         "min": 2,
 * //         "max": 5
 * //       }
 * //     ]
 * //   },
 * //   {
 * //     "name": "d",
 * //     "value": 4.4,
 * //     "items": [
 * //       {
 * //         "min": 2,
 * //         "max": 5
 * //       }
 * //     ]
 * //   },
 * //   {
 * //     "name": "e",
 * //     "value": 5.5
 * //   },
 * //   {
 * //     "name": "f",
 * //     "value": 6.6
 * //   }
 * // ]
 *
 * let arr2 = [
 *     {
 *         name: 'a',
 *         value: 1.1,
 *     },
 *     {
 *         name: 'b',
 *         value: 2.2,
 *     },
 *     {
 *         name: 'c',
 *         value: 3.3,
 *     },
 *     {
 *         name: 'd',
 *         value: 4.4,
 *     },
 *     {
 *         name: 'e',
 *         value: 5.5,
 *     },
 *     {
 *         name: 'f',
 *         value: 6.6,
 *     },
 * ]
 * let mm2 = [
 *     {
 *         rmin: 0,
 *         rmax: 2,
 *     },
 *     {
 *         rmin: 2,
 *         rmax: 5,
 *     },
 * ]
 * console.log(JSON.stringify(arrLookupByMaxmin(arr2, mm2, { keyMin: 'rmin', keyMax: 'rmax' }), null, 2))
 * // => [
 * //   {
 * //     "name": "a",
 * //     "value": 1.1,
 * //     "items": [
 * //       {
 * //         "rmin": 0,
 * //         "rmax": 2
 * //       }
 * //     ]
 * //   },
 * //   {
 * //     "name": "b",
 * //     "value": 2.2,
 * //     "items": [
 * //       {
 * //         "rmin": 2,
 * //         "rmax": 5
 * //       }
 * //     ]
 * //   },
 * //   {
 * //     "name": "c",
 * //     "value": 3.3,
 * //     "items": [
 * //       {
 * //         "rmin": 2,
 * //         "rmax": 5
 * //       }
 * //     ]
 * //   },
 * //   {
 * //     "name": "d",
 * //     "value": 4.4,
 * //     "items": [
 * //       {
 * //         "rmin": 2,
 * //         "rmax": 5
 * //       }
 * //     ]
 * //   },
 * //   {
 * //     "name": "e",
 * //     "value": 5.5
 * //   },
 * //   {
 * //     "name": "f",
 * //     "value": 6.6
 * //   }
 * // ]
 *
 * let arr3 = [
 *     {
 *         name: 'a',
 *         data: 1.1,
 *     },
 *     {
 *         name: 'b',
 *         data: 2.2,
 *     },
 *     {
 *         name: 'c',
 *         data: 3.3,
 *     },
 *     {
 *         name: 'd',
 *         data: 4.4,
 *     },
 *     {
 *         name: 'e',
 *         data: 5.5,
 *     },
 *     {
 *         name: 'f',
 *         data: 6.6,
 *     },
 * ]
 * let mm3 = [
 *     {
 *         min: 0,
 *         max: 2,
 *     },
 *     {
 *         min: 2,
 *         max: 5,
 *     },
 * ]
 * console.log(JSON.stringify(arrLookupByMaxmin(arr3, mm3, { keyValue: 'data' }), null, 2))
 * // => [
 * //   {
 * //     "name": "a",
 * //     "data": 1.1,
 * //     "items": [
 * //       {
 * //         "min": 0,
 * //         "max": 2
 * //       }
 * //     ]
 * //   },
 * //   {
 * //     "name": "b",
 * //     "data": 2.2,
 * //     "items": [
 * //       {
 * //         "min": 2,
 * //         "max": 5
 * //       }
 * //     ]
 * //   },
 * //   {
 * //     "name": "c",
 * //     "data": 3.3,
 * //     "items": [
 * //       {
 * //         "min": 2,
 * //         "max": 5
 * //       }
 * //     ]
 * //   },
 * //   {
 * //     "name": "d",
 * //     "data": 4.4,
 * //     "items": [
 * //       {
 * //         "min": 2,
 * //         "max": 5
 * //       }
 * //     ]
 * //   },
 * //   {
 * //     "name": "e",
 * //     "data": 5.5
 * //   },
 * //   {
 * //     "name": "f",
 * //     "data": 6.6
 * //   }
 * // ]
 *
 * let arr4 = [
 *     {
 *         name: 'a',
 *         value: 1.1,
 *     },
 *     {
 *         name: 'b',
 *         value: 2.2,
 *     },
 *     {
 *         name: 'c',
 *         value: 3.3,
 *     },
 *     {
 *         name: 'd',
 *         value: 4.4,
 *     },
 *     {
 *         name: 'e',
 *         value: 5.5,
 *     },
 *     {
 *         name: 'f',
 *         value: 6.6,
 *     },
 * ]
 * let mm4 = [
 *     {
 *         min: 0,
 *         max: 2,
 *     },
 *     {
 *         min: 2,
 *         max: 5,
 *     },
 * ]
 * console.log(JSON.stringify(arrLookupByMaxmin(arr4, mm4, { keyItems: 'res' }), null, 2))
 * // => [
 * //   {
 * //     "name": "a",
 * //     "value": 1.1,
 * //     "res": [
 * //       {
 * //         "min": 0,
 * //         "max": 2
 * //       }
 * //     ]
 * //   },
 * //   {
 * //     "name": "b",
 * //     "value": 2.2,
 * //     "res": [
 * //       {
 * //         "min": 2,
 * //         "max": 5
 * //       }
 * //     ]
 * //   },
 * //   {
 * //     "name": "c",
 * //     "value": 3.3,
 * //     "res": [
 * //       {
 * //         "min": 2,
 * //         "max": 5
 * //       }
 * //     ]
 * //   },
 * //   {
 * //     "name": "d",
 * //     "value": 4.4,
 * //     "res": [
 * //       {
 * //         "min": 2,
 * //         "max": 5
 * //       }
 * //     ]
 * //   },
 * //   {
 * //     "name": "e",
 * //     "value": 5.5
 * //   },
 * //   {
 * //     "name": "f",
 * //     "value": 6.6
 * //   }
 * // ]
 *
 * let arr5 = [
 *     {
 *         name: 'a',
 *         value: 1.1,
 *     },
 *     {
 *         name: 'b',
 *         value: 2.2,
 *     },
 *     {
 *         name: 'c',
 *         value: 3.3,
 *     },
 *     {
 *         name: 'd',
 *         value: 4.4,
 *     },
 *     {
 *         name: 'e',
 *         value: 5.5,
 *     },
 *     {
 *         name: 'f',
 *         value: 6.6,
 *     },
 * ]
 * let mm5 = [
 *     {
 *         name: 'x1',
 *         min: 0,
 *         max: 2,
 *     },
 *     {
 *         name: 'x2',
 *         min: 2,
 *         max: 5,
 *     },
 * ]
 * console.log(JSON.stringify(arrLookupByMaxmin(arr5, mm5, {
 *     keyItems: 'res',
 *     beforeAddResult: (m) => {
 *         return m.name
 *     }
 * }), null, 2))
 * // => [
 * //   {
 * //     "name": "a",
 * //     "value": 1.1,
 * //     "res": [
 * //       "x1"
 * //     ]
 * //   },
 * //   {
 * //     "name": "b",
 * //     "value": 2.2,
 * //     "res": [
 * //       "x2"
 * //     ]
 * //   },
 * //   {
 * //     "name": "c",
 * //     "value": 3.3,
 * //     "res": [
 * //       "x2"
 * //     ]
 * //   },
 * //   {
 * //     "name": "d",
 * //     "value": 4.4,
 * //     "res": [
 * //       "x2"
 * //     ]
 * //   },
 * //   {
 * //     "name": "e",
 * //     "value": 5.5
 * //   },
 * //   {
 * //     "name": "f",
 * //     "value": 6.6
 * //   }
 * // ]
 *
 * let arr6 = [
 *     {
 *         name: 'a',
 *         value: 1.1,
 *     },
 *     {
 *         name: 'b',
 *         value: 2.2,
 *     },
 *     {
 *         name: 'c',
 *         value: 3.3,
 *     },
 *     {
 *         name: 'd',
 *         value: 4.4,
 *     },
 *     {
 *         name: 'e',
 *         value: 5.5,
 *     },
 *     {
 *         name: 'f',
 *         value: 6.6,
 *     },
 * ]
 * let mm6 = [
 *     {
 *         min: 1.1,
 *         minType: '>',
 *         max: 2.2,
 *         maxType: '<=',
 *     },
 *     {
 *         min: 2.2,
 *         minType: '>=',
 *         max: 5.5,
 *         maxType: '<',
 *     },
 * ]
 * console.log(JSON.stringify(arrLookupByMaxmin(arr6, mm6), null, 2))
 * // => [
 * //   {
 * //     "name": "a",
 * //     "value": 1.1
 * //   },
 * //   {
 * //     "name": "b",
 * //     "value": 2.2,
 * //     "items": [
 * //       {
 * //         "min": 1.1,
 * //         "minType": ">",
 * //         "max": 2.2,
 * //         "maxType": "<="
 * //       },
 * //       {
 * //         "min": 2.2,
 * //         "minType": ">=",
 * //         "max": 5.5,
 * //         "maxType": "<"
 * //       }
 * //     ]
 * //   },
 * //   {
 * //     "name": "c",
 * //     "value": 3.3,
 * //     "items": [
 * //       {
 * //         "min": 2.2,
 * //         "minType": ">=",
 * //         "max": 5.5,
 * //         "maxType": "<"
 * //       }
 * //     ]
 * //   },
 * //   {
 * //     "name": "d",
 * //     "value": 4.4,
 * //     "items": [
 * //       {
 * //         "min": 2.2,
 * //         "minType": ">=",
 * //         "max": 5.5,
 * //         "maxType": "<"
 * //       }
 * //     ]
 * //   },
 * //   {
 * //     "name": "e",
 * //     "value": 5.5
 * //   },
 * //   {
 * //     "name": "f",
 * //     "value": 6.6
 * //   }
 * // ]
 *
 */
function arrLookupByMaxmin(arr, maxmins, opt = {}) {

    //keyMax in maxmins
    let keyMax = get(opt, 'keyMax')
    if (!isestr(keyMax)) {
        keyMax = 'max'
    }

    //keyMin in maxmins
    let keyMin = get(opt, 'keyMin')
    if (!isestr(keyMin)) {
        keyMin = 'min'
    }

    //keyValue in arr
    let keyValue = get(opt, 'keyValue')
    if (!isestr(keyValue)) {
        keyValue = 'value'
    }

    //keyItems for items from arr
    let keyItems = get(opt, 'keyItems')
    if (!isestr(keyItems)) {
        keyItems = 'items'
    }

    //beforeAddResult for items from maxmins
    let beforeAddResult = get(opt, 'beforeAddResult', null)

    //check
    if (!isearr(arr)) {
        return []
    }
    if (!isearr(maxmins)) {
        return []
    }

    //isObjArray
    let isObjArray = iseobj(get(arr, 0))
    if (!isObjArray) {
        return []
    }

    //rs
    let rs = cloneDeep(arr)
    each(rs, (v, k) => {
        let value = get(v, keyValue)
        if (isnum(value)) {
            value = cdbl(value)
        }
        else {
            // console.log(`can not find keyValue[${keyValue}] in element of arr(object array)`)
        }
        if (isNumber(value)) {
            each(maxmins, (mm, kmm) => {

                //rmax, rmin
                let rmax = get(mm, keyMax, null)
                let rmin = get(mm, keyMin, null)

                //check
                if (rmax !== null && rmin !== null) {

                    //check
                    if (isnum(rmax) && isnum(rmin)) {

                        //maxType in mm
                        let maxType = get(mm, 'maxType')
                        if (maxType !== '<=' && maxType !== '<') {
                            maxType = '<='
                        }

                        //minType in mm
                        let minType = get(mm, 'minType')
                        if (minType !== '>=' && minType !== '>') {
                            minType = '>='
                        }

                        //cdbl
                        rmax = cdbl(rmax)
                        rmin = cdbl(rmin)

                        //bmin
                        let bmin
                        if (minType === '>=') {
                            bmin = value >= rmin
                        }
                        else {
                            bmin = value > rmin
                        }

                        //bmax
                        let bmax
                        if (maxType === '<=') {
                            bmax = value <= rmax
                        }
                        else {
                            bmax = value < rmax
                        }

                        //check
                        if (bmin && bmax) {

                            //beforeAddResult
                            if (isfun(beforeAddResult)) {
                                mm = beforeAddResult(mm, rs[k], k)
                            }

                            //check
                            if (!haskey(rs[k], keyItems)) {
                                rs[k][keyItems] = []
                            }

                            //save
                            rs[k][keyItems].push(mm)

                        }
                    }
                    else {
                        // console.log(`maxmins['${kmm}'][${keyMax}] or maxmins['${kmm}'][${keyMin}] is not a number`)
                    }

                }
                else {
                    // console.log(`can not find keyMax[${keyMax}] or keyMin[${keyMin}] in element of maxmins`)
                }

            })
        }
    })

    return rs
}


export default arrLookupByMaxmin