Skip to content

数据处理

a-calc 在数据处理、报表计算等场景同样表现出色。

表格数据计算

行计算

javascript
import { calc } from 'a-calc'

const tableData = [
  { product: '商品A', price: 100, quantity: 5, discount: 0.9 },
  { product: '商品B', price: 200, quantity: 3, discount: 0.85 },
  { product: '商品C', price: 150, quantity: 8, discount: 0.95 }
]

// 计算每行小计
const withSubtotal = tableData.map(row => ({
  ...row,
  subtotal: calc('price * quantity * discount | =2', row)
}))

// [
//   { product: '商品A', ..., subtotal: '450.00' },
//   { product: '商品B', ..., subtotal: '510.00' },
//   { product: '商品C', ..., subtotal: '1140.00' }
// ]
Ctrl+D 选择词, Ctrl+/ 注释

列汇总

javascript
import { calc_sum } from 'a-calc'

const salesData = [
  { month: '1月', revenue: 100000, cost: 60000 },
  { month: '2月', revenue: 120000, cost: 70000 },
  { month: '3月', revenue: 150000, cost: 85000 }
]

// 列汇总
const summary = {
  totalRevenue: calc_sum('revenue | ,', salesData),      // '370,000'
  totalCost: calc_sum('cost | ,', salesData),            // '215,000'
  totalProfit: calc_sum('revenue - cost | ,', salesData) // '155,000'
}

计算占比

javascript
import { calc, calc_sum } from 'a-calc'

const categoryData = [
  { category: '电子产品', sales: 50000 },
  { category: '服装', sales: 30000 },
  { category: '食品', sales: 20000 }
]

const total = calc_sum('sales', categoryData)

const withPercentage = categoryData.map(item => ({
  ...item,
  percentage: calc('sales / total * 100 | ~5=2', {
    sales: item.sales,
    total
  }) + '%'
}))

// [
//   { category: '电子产品', sales: 50000, percentage: '50.00%' },
//   { category: '服装', sales: 30000, percentage: '30.00%' },
//   { category: '食品', sales: 20000, percentage: '20.00%' }
// ]

统计计算

平均值

javascript
import { calc, calc_sum } from 'a-calc'

const scores = [
  { name: '张三', score: 85 },
  { name: '李四', score: 92 },
  { name: '王五', score: 78 },
  { name: '赵六', score: 88 }
]

const sum = calc_sum('score', scores)
const avg = calc('sum / count | ~5=2', {
  sum,
  count: scores.length
})
// '85.75'

增长率

javascript
import { calc } from 'a-calc'

const monthlyData = [
  { month: '1月', value: 10000 },
  { month: '2月', value: 12000 },
  { month: '3月', value: 11500 },
  { month: '4月', value: 15000 }
]

// 计算环比增长率
const withGrowth = monthlyData.map((item, index) => {
  if (index === 0) {
    return { ...item, growth: '-' }
  }

  const prev = monthlyData[index - 1].value
  const growth = calc('(current - prev) / prev * 100 | ~5=2', {
    current: item.value,
    prev
  })

  return {
    ...item,
    growth: growth + '%'
  }
})

// [
//   { month: '1月', value: 10000, growth: '-' },
//   { month: '2月', value: 12000, growth: '20.00%' },
//   { month: '3月', value: 11500, growth: '-4.17%' },
//   { month: '4月', value: 15000, growth: '30.43%' }
// ]
Ctrl+D 选择词, Ctrl+/ 注释

数据转换

单位换算

javascript
import { calc } from 'a-calc'

// 字节转换
function formatBytes(bytes) {
  if (calc(`${bytes} < 1024 | !n`)) {
    return bytes + ' B'
  }
  if (calc(`${bytes} < 1048576 | !n`)) {
    return calc('bytes / 1024 | ~5=2', { bytes }) + ' KB'
  }
  if (calc(`${bytes} < 1073741824 | !n`)) {
    return calc('bytes / 1048576 | ~5=2', { bytes }) + ' MB'
  }
  return calc('bytes / 1073741824 | ~5=2', { bytes }) + ' GB'
}

formatBytes(500)          // '500 B'
formatBytes(1536)         // '1.50 KB'
formatBytes(1572864)      // '1.50 MB'
formatBytes(1610612736)   // '1.50 GB'

时间转换

javascript
import { calc } from 'a-calc'

// 秒转时分秒
function formatDuration(seconds) {
  const hours = calc('seconds // 3600 | =0', { seconds })
  const minutes = calc('(seconds % 3600) // 60 | =0', { seconds })
  const secs = calc('seconds % 60 | =0', { seconds })

  return `${hours}:${String(minutes).padStart(2, '0')}:${String(secs).padStart(2, '0')}`
}

formatDuration(3661)      // '1:01:01'
formatDuration(7325)      // '2:02:05'

数据验证

范围验证

javascript
import { calc } from 'a-calc'

function validateRange(value, min, max) {
  const isValid = calc(`${value} >= ${min}`, {}) &&
                  calc(`${value} <= ${max}`, {})

  return {
    valid: isValid,
    value: calc('value | =2', { value }),
    message: isValid ? '' : `值必须在 ${min} 到 ${max} 之间`
  }
}

validateRange(50, 0, 100)   // { valid: true, value: '50.00', message: '' }
validateRange(150, 0, 100)  // { valid: false, value: '150.00', message: '...' }

精度验证

javascript
import { calc } from 'a-calc'

// 检查两个浮点数是否相等
function floatEquals(a, b, precision = 10) {
  const diff = calc(`(${a}) - (${b})`, {})
  const absDiff = Math.abs(parseFloat(diff))
  const threshold = Math.pow(10, -precision)

  return absDiff < threshold
}

floatEquals(0.1 + 0.2, 0.3)  // true (使用 calc 计算后比较)

// JavaScript 原生比较会失败
0.1 + 0.2 === 0.3            // false

批量处理

使用 calc_wrap 批处理

javascript
import { calc_wrap } from 'a-calc'

const data = [
  { a: 10, b: 20 },
  { a: 30, b: 40 },
  { a: 50, b: 60 }
]

// 创建计算函数
const calcSum = calc_wrap('a + b | =2')
const calcProduct = calc_wrap('a * b | =2')
const calcRatio = calc_wrap('a / b * 100 | ~5=2')

// 批量计算
const results = data.map(item => ({
  ...item,
  sum: calcSum(item),
  product: calcProduct(item),
  ratio: calcRatio(item) + '%'
}))

// [
//   { a: 10, b: 20, sum: '30.00', product: '200.00', ratio: '50.00%' },
//   { a: 30, b: 40, sum: '70.00', product: '1200.00', ratio: '75.00%' },
//   { a: 50, b: 60, sum: '110.00', product: '3000.00', ratio: '83.33%' }
// ]

基于 MIT 许可发布