没有“if-else”或“switch-case”的度量转换算法

时间:2013-07-09 12:29:07

标签: java algorithm

我想编写一个可以将一个单元转换为另一个单元的程序。假设我有2种方法。第一种方法可以做度量转换,第二种方法可以做权重转换。例如;

1。 long km=metricConvLength(long mil,Enum.mil,Enum.km);//first method

2。 long agirlik=metricConvWeight(long kg,Enum.mil,Enum.km);//second method

我想对这些变量使用 Enum 结构。 我的程序可以转换这些东西和对立面;

  • sea mile-km
  • sea mile-mile
  • 英尺 - 公里
  • feet-mil
  • pound- kg
  • ons- gr
  • inc - cm
  • yard - m
  • knot-km

我的问题:我不想使用if-elseswitch-case结构进行转换。(因为如果我使用if-else结构,我的代码看起来像这样如果我使用这些结构,那么我需要超过50个if-else结构。这是研究。)

我可以在不使用if-else或switch-case的情况下为这些转换编写算法。 我的目的是减少代码,减少工作量。有关算法的任何提示吗?

5 个答案:

答案 0 :(得分:10)

您不需要if-then-else - 实际上,您的程序中不需要控制语句。您所需要的只是一个查找表 - Map可将您的单位枚举转换为double转换因子,以便将度量单位乘以您获得的空间单位米的转换因子,以及千克对于重量单位。相反,按该因子划分米可以得到所需的单位。

掌握了这张地图后,您可以对所有单位对进行转换:

  • 查找源单位的转换因子Cs
  • 查找目标单元的转换因子Cd
  • 返回value * Cs / Cd作为结果。

例如,假设您要处理米,码,英寸和英尺。你的地图看起来像这样:

  • m - 1.0
  • y - 0.9144
  • in - 0.0254
  • ft - 0.3048

现在假设您要将7.5码转换为英尺:

  • 查找Cs = 0.9144
  • 查找Cd = 0.3048
  • 计算并返回Res = 7.5 * 0.9144 / 0.3048 = 22.5

答案 1 :(得分:2)

我建议引入一种类型" MetricValue"。软件工程的历史充满了程序员忘记了他们使用的价值单位的项目。由此产生的灾难是众所周知的。

此外,我会提出一个不可变类,因为它使许多设计方面更简单。

在首次将所有值转换为基本单位然后将值转换为目标单位时,定义基本单位会对您有很大帮助。您也可以应用矩阵,但是您需要预先计算值。矩阵的大小将为n ^ 2,而从基本单位到基本单位的转换仅保留n个值。如果您使用耗费资源的复杂转换公式,那么它是有道理的。否则,这些努力的好处(太小)将会很小。

这段代码怎么样?

public class MetricValue {

    public static enum Unit {
        m(1.0d), y(0.9144d), in(0.0254d), ft(0.3048d);

        final static Unit baseUnit = m;
        final double perBaseUnit;

        private Unit(double inM) {
            this.perBaseUnit = inM;
        }

        public double fromBaseUnit(double value) {
            return value / perBaseUnit;
        }

        public double toBaseUnit(double value) {
            return value * perBaseUnit;
        }
    }

    final double value;
    final Unit unit;

    public MetricValue(double value, Unit unit) {
        super();
        this.value = value;
        this.unit = unit;
    }

    public MetricValue to(Unit newUnit) {
        Unit oldUnit = this.unit;
        return new MetricValue(newUnit.fromBaseUnit(oldUnit.toBaseUnit(value)),
                newUnit);
    }

    @Override
    public String toString() {
        return value + " " + unit.name();
    }

    public static void main(String[] args) {
        MetricValue distanceInM = new MetricValue(1, Unit.m);
        MetricValue distanceInFt = new MetricValue(6, Unit.ft);
        System.out.println(distanceInM);

        System.out.println(distanceInM.to(Unit.y));
        System.out.println(distanceInM.to(Unit.y).to(Unit.m));
        System.out.println(distanceInM.to(Unit.y).to(Unit.ft));
        System.out.println(distanceInFt.to(Unit.m));
    }
}

您可以在计算时使用原始值并创建新的指标值。您还可以为基本或复杂的算术运算添加操作。

这里省略了吸气剂。

答案 2 :(得分:1)

将它们的相对值与你的枚举中的变量相关联(我猜你有一个用于距离,一个用于权重),如enum Distances { CM(100), M(100*1000), IN(254) },...然后你只需得到所提供值的比率,乘以通过第一个参数,你得到了你的结果。如果您想要一个合适的精度,请使用基础100或1000作为最小单位。

答案 3 :(得分:1)

选择其中一个单位作为“基础”单位(一个用于重量,例如 gr ;一个用于距离,例如 m )。然后使用每个值的转化率为您的枚举添加方法toBaseUnitfromBaseUnit

不涉及“ifs”,您的转换方法如下所示:

ResultingUnit.fromBaseUnit(originalUnit.toBaseUnit(value));

示例枚举:

public enum Distance {
    METER(new BigDecimal("1.0")), // Base Unit is METER
    KM(new BigDecimal("1E3")),
    CM(new BigDecimal("1E-2"));

    private final static MathContext MC = 
          new MathContext(30, RoundingMode.HALF_EVEN);
    private final BigDecimal conversionRatio;

    Distance(BigDecimal conversionRatio) {
        this.conversionRatio = conversionRatio;
    }

    long fromBaseUnit(BigDecimal baseUnit) {
        return baseUnit.divide(conversionRatio, MC).longValue();
    }

    // returns BigDecimal to avoid rounding two times
    // and possible division by zero
    BigDecimal toBaseUnit(long originalUnit) {
        return BigDecimal.valueOf(originalUnit).multiply(conversionRatio);
    }
}

适应转换方法:

public long metricConvLength(long value, Distance orgUnit, Distance resultUnit) {
    return resultUnit.fromBaseUnit(orgUnit.toBaseUnit(value));
}  

除了稍快一些(通过避免Map查找和循环枚举值),这种方法的主要优点是,如果您需要更复杂的转换操作(例如,Temperature枚举使用Celsius,Farenheit和Kelvin),您可以覆盖枚举值正文中的fromBaseUnittoBaseUnit


Working Example

我已将BigDecimal用于转换率和内部计算,以便更好地控制精度和舍入行为。

答案 4 :(得分:1)

在您的枚举中,您可以在枚举类型上实现fromString方法,假设您的枚举名称为“距离”

private static final Map<String,Distances> stringToEnum = new HashMap<String,Distances>;

初始化地图:

  static{
        for(Distances distance: values()) {
            stringToEnum.put(distance.toString(),distance);
        }
  }

返回字符串的enumType:

public static Distances getDistance(String stringValue){
    return stringToEnum.get(stringValue);
}

在您的方法中,您可以直接传入:

Distance.getDistance("feet").getCalculatedDistance()