জাভাতে 1200 থেকে 1.2k ফর্ম্যাট করার বিষয়ে কীভাবে যাবেন


156

আমি জাভা সহ তাদের পরবর্তী সংখ্যায় ফর্ম্যাট করতে চাই:

1000 to 1k
5821 to 5.8k
10500 to 10k
101800 to 101k
2000000 to 2m
7800000 to 7.8m
92150000 to 92m
123200000 to 123m

ডানদিকে সংখ্যাটি দীর্ঘ বা পূর্ণসংখ্যার বাম দিকে সংখ্যাটি স্ট্রিং হবে। আমি কিভাবে এই কাছে যাওয়া উচিত। আমি এর জন্য ইতিমধ্যে সামান্য অ্যালগরিদম করেছি তবে আমি ভেবেছিলাম যে ইতিমধ্যে এমন কিছু উদ্ভাবিত হতে পারে যা এতে ভাল কাজ করে এবং যদি আমি বিলিয়ন এবং ট্রিলিয়ন ডলারের কাজ শুরু করি তবে অতিরিক্ত পরীক্ষার প্রয়োজন নেই :)

অতিরিক্ত আবশ্যক:

  • ফর্ম্যাটে সর্বাধিক 4 টি অক্ষর থাকা উচিত
  • উপরের অর্থ 1.1k ঠিক আছে 11.2k নয়। 7.8 মিটারের জন্য একই 19.1 মিটি ঠিক নেই। দশমিক পয়েন্টের পূর্বে কেবল একটি অঙ্কের দশমিক বিন্দু থাকার অনুমতি রয়েছে। দশমিক বিন্দুর আগে দুটি অঙ্ক অর্থ দশমিক বিন্দুর পরে অঙ্কগুলি নয়।
  • কোন গোলাকার প্রয়োজন হয় না। (কে এবং এম সংযুক্ত সংখ্যাসমূহ আরও অ্যানালগ गेজ যুক্তিযুক্ত সুনির্দিষ্ট নিবন্ধটি নির্দেশ করে না। সুতরাং আপনি ক্যাশেড ফলাফলের দিকে তাকিয়ে থাকা সত্ত্বেও পরিবর্তনগুলি বেশিরভাগ সংখ্যাকে বাড়িয়ে তুলতে বা ডিক্রি করতে পারার কারণে গোলাকার অপ্রাসঙ্গিক)

1
কারও কাছে যদি গ্রন্থাগার না থাকে তবে আপনি কি আপনার কোড পোস্ট করতে আপত্তি করবেন?
গ্রাম্যমান

1
এটি সহায়তা করতে পারে, যদিও এটি ডুপ নয়। stackoverflow.com/questions/529432
rfeak

1
@ ম্যাট আমি কৌতূহলী ছিলাম আপনি আগে কী সমাধান ব্যবহার করছিলেন। যদি আপনি কিছু মনে করেন না তবে আপনি এটি উত্তর হিসাবে পোস্টও করবেন।
jjd

1
এর পেছনের ধারণাটি No rounding is necessaryআমার কাছে অযৌক্তিক বলে মনে হচ্ছে। এটা কি কেবল বিষয়গুলিকে জটিল করার জন্য? এটিকে পুনরায় প্রকাশ করা কি ভাল হবে না Rounding is not necessary, but welcome?
নেকড়ে

1
যদি আপনি খেয়াল করেননি যে কে এবং এম সংযুক্ত সংখ্যার সাথে প্রদর্শিত হচ্ছে তবে এনালগ गेজের বেশি সংখ্যার সাথে যুক্তিটির সঠিক নিবন্ধটি নির্দেশ করে না। অতএব আপনি ক্যাশেড ফলাফলের দিকে তাকিয়ে থাকা সত্ত্বেও বৃত্তাকারটি মূলত ভেরিয়েবলের প্রকৃতির কারণে অপ্রাসঙ্গিক increase
মাদুর বি।

উত্তর:


155

এখানে এমন একটি সমাধান রয়েছে যা কোনও দীর্ঘ মূল্যের জন্য কাজ করে এবং আমি বেশ পঠনযোগ্য দেখতে পাই (মূল যুক্তিটি formatপদ্ধতির নীচে তিনটি লাইনে করা হয় )।

এটি TreeMapযথাযোগ্য প্রত্যয়টি খুঁজে পেতে সহায়তা করে। এটি যে আমি লিখেছিলাম অ্যারে ব্যবহার করেছিলাম এবং এটি পড়তে আরও কঠিন ছিল তার আগের সমাধানের চেয়ে এটি আশ্চর্যজনকভাবে আরও কার্যকর।

private static final NavigableMap<Long, String> suffixes = new TreeMap<> ();
static {
  suffixes.put(1_000L, "k");
  suffixes.put(1_000_000L, "M");
  suffixes.put(1_000_000_000L, "G");
  suffixes.put(1_000_000_000_000L, "T");
  suffixes.put(1_000_000_000_000_000L, "P");
  suffixes.put(1_000_000_000_000_000_000L, "E");
}

public static String format(long value) {
  //Long.MIN_VALUE == -Long.MIN_VALUE so we need an adjustment here
  if (value == Long.MIN_VALUE) return format(Long.MIN_VALUE + 1);
  if (value < 0) return "-" + format(-value);
  if (value < 1000) return Long.toString(value); //deal with easy case

  Entry<Long, String> e = suffixes.floorEntry(value);
  Long divideBy = e.getKey();
  String suffix = e.getValue();

  long truncated = value / (divideBy / 10); //the number part of the output times 10
  boolean hasDecimal = truncated < 100 && (truncated / 10d) != (truncated / 10);
  return hasDecimal ? (truncated / 10d) + suffix : (truncated / 10) + suffix;
}

পরীক্ষার কোড

public static void main(String args[]) {
  long[] numbers = {0, 5, 999, 1_000, -5_821, 10_500, -101_800, 2_000_000, -7_800_000, 92_150_000, 123_200_000, 9_999_999, 999_999_999_999_999_999L, 1_230_000_000_000_000L, Long.MIN_VALUE, Long.MAX_VALUE};
  String[] expected = {"0", "5", "999", "1k", "-5.8k", "10k", "-101k", "2M", "-7.8M", "92M", "123M", "9.9M", "999P", "1.2P", "-9.2E", "9.2E"};
  for (int i = 0; i < numbers.length; i++) {
    long n = numbers[i];
    String formatted = format(n);
    System.out.println(n + " => " + formatted);
    if (!formatted.equals(expected[i])) throw new AssertionError("Expected: " + expected[i] + " but found: " + formatted);
  }
}

1
সুন্দর সমাধান। দেখে মনে হচ্ছে আপনি সেই প্রকৃত বিশাল সংখ্যক (চতুর্ভুজ, কুইন্টিলিয়ন ইত্যাদি) এর জন্য আরও আরও প্রত্যয় যুক্ত করতে পারেন এবং আউটপুটটি স্কেল অবিরত থাকবে।
সাইফার

আপনার কোড ঋণাত্মক সংখ্যা সঙ্গে বেশ সঠিক নয়: -5821হিসাবে ফর্ম্যাট করা উচিত -5kনয়, -5.8k
std.denis

1
@ std.denis ওপিতে নেতিবাচক সংখ্যার বিন্যাস কীভাবে করা যায় তা নির্দেশ করে নি। আমি তাদের ইতিবাচক সংখ্যার মতো ফর্ম্যাট করার সিদ্ধান্ত নিয়েছি তবে -একই সংখ্যার উল্লেখযোগ্য সংখ্যা রাখতে পূর্ববর্তী করে রেখেছি । অন্যান্য অপশন রয়েছে ...
অ্যাসিরিয়াস

1
প্রথম: আমি খারাপ মন্তব্যগুলি মুছলাম, কারণ এটি অবশ্যই আপনার দোষ নয়। দ্বিতীয়: এটি এমন সমস্যা নয় যে ভাল উত্তরগুলি যতক্ষণ অন্যের মতো বেশি পায় ততক্ষণ তা যথেষ্ট মনোযোগ পায় না, তবে এটি হ'ল আপনাকে প্রায়শই ভাল উত্তরের জন্য খনন করতে হয় এবং কেবল কিছু ভুল, খারাপ বা জেনেরিক উত্তর উজ্জীবিত হয় (সত্যই নতুন জিনিস শিখতে খারাপ)। এবং ইতিমধ্যে অনেক উত্তর রয়েছে এমন লোকেরা যখন জমিদারি জারি করেন তাদের জন্য আমি কী স্পষ্ট করে তা আরও স্পষ্ট করে নির্দিষ্ট করে প্রত্যাশা করতাম এবং তারপরে উত্তরটি যা মানদণ্ডে সবচেয়ে ভাল ফিট করে তা বেছে
নেব

1
কিন্তু পুরো বিশ্ব কি এই স্ট্যান্ডার্ডটি বুঝতে পারে? আপনি যদি বিশ্বের প্রত্যেকের জন্য অ্যাপ তৈরি করেন তবে সাবধান হন। ইংরেজির জন্য এটি 10 এম তবে রাশিয়ানদের জন্য এটি 10 млн এবং আরও
ইউজার 924

101

আমি জানি, এটি দেখতে আরও অনেকটা সি প্রোগ্রামের মতো, তবে এটি সুপার লাইটওয়েট!

public static void main(String args[]) {
    long[] numbers = new long[]{1000, 5821, 10500, 101800, 2000000, 7800000, 92150000, 123200000, 9999999};
    for(long n : numbers) {
        System.out.println(n + " => " + coolFormat(n, 0));
    }
}

private static char[] c = new char[]{'k', 'm', 'b', 't'};

/**
 * Recursive implementation, invokes itself for each factor of a thousand, increasing the class on each invokation.
 * @param n the number to format
 * @param iteration in fact this is the class from the array c
 * @return a String representing the number n formatted in a cool looking way.
 */
private static String coolFormat(double n, int iteration) {
    double d = ((long) n / 100) / 10.0;
    boolean isRound = (d * 10) %10 == 0;//true if the decimal part is equal to 0 (then it's trimmed anyway)
    return (d < 1000? //this determines the class, i.e. 'k', 'm' etc
        ((d > 99.9 || isRound || (!isRound && d > 9.99)? //this decides whether to trim the decimals
         (int) d * 10 / 10 : d + "" // (int) d * 10 / 10 drops the decimal
         ) + "" + c[iteration]) 
        : coolFormat(d, iteration+1));

}

এটি ফলাফল:

1000 => 1k
5821 => 5.8k
10500 => 10k
101800 => 101k
2000000 => 2m
7800000 => 7.8m
92150000 => 92m
123200000 => 123m
9999999 => 9.9m

16
অবরুদ্ধ কোড। আজকাল আমাদের এ জাতীয় কোড করতে হবে না। প্রত্যাশার মতো কাজ করতে পারে তবে আমি রজার সি মার্টিন: ক্লিন কোড
আন্দ্রেয়াস ডলক

29
Obfuscated? আমি আপনার ক্ষমা প্রার্থনা করছি, তবে আপনি সম্ভবত একটি বই পড়েছেন এবং মনে করেন আপনি আজকাল কোনওভাবে আলাদা কোড করতে পারেন। এটি সম্পর্কে জোয়েলকে ( joelonsoftware.com/articles/ThePerilsofJavaSchools.html ) বলুন । আমার পদ্ধতির গতির কাছাকাছি যেতে আপনি যে কোনও কোডই সম্ভবত লিখতে পারেন সাহস!
এলিজা সাউনকাইন

11
ডি, সি, এন ভেরিয়েবলগুলি আরও বেশি পঠনযোগ্য (দ্রুত বোঝার) সাথে পরিবর্তন করা এই কোডটি আমার দৃষ্টিতে শালীন করে তোলে
জেনাদি রেয়াবকিন

5
পারফরম্যান্স নিয়ে কেন এই আবেশ? পারফরম্যান্সের কথা চিন্তা করে কেন কেউ এই ধরণের রূপান্তরগুলির বিশাল সংখ্যক ব্যবহার করতে চায় ...? পঠনযোগ্যতা প্রথম, প্রয়োজন হলে পারফরম্যান্স টুইট।
আমোস এম কার্পেন্টার

10
আমাকে @ অ্যামোসএম.কর্পেন্ডারের সাথে একমত হতে হবে। 4 বছর আগে আমি যখন এই উত্তরটি লিখেছিলাম তখন কোড রক্ষণাবেক্ষণ সম্পর্কে খুব কমই জানতাম। সাধারণভাবে বলতে গেলে এটি অপ্টিমাইজ করা খারাপ নয়, তবে পঠনযোগ্যতা প্রথমে আসে। যাইহোক, এটি এত খারাপ পারফরম্যান্স অনুযায়ী নয়: একজন মারাকাকে লিখেছেন তার চেয়ে 5 গুণ ধীর নয় - এটি প্রায় একই রকম (আমি এখানে একটি মানদণ্ডের জন্য কিছু সমাধান রেখেছি github.com/esaounkine/number-format- মানদণ্ড )।
এলিজা সাউনকাইন

43

এখানে একটি সমাধান যা ডেসিমালফোর্মের ইঞ্জিনিয়ারিং স্বরলিপি ব্যবহার করে:

public static void main(String args[]) {
    long[] numbers = new long[]{7, 12, 856, 1000, 5821, 10500, 101800, 2000000, 7800000, 92150000, 123200000, 9999999};
    for(long number : numbers) {
        System.out.println(number + " = " + format(number));
    }
}

private static String[] suffix = new String[]{"","k", "m", "b", "t"};
private static int MAX_LENGTH = 4;

private static String format(double number) {
    String r = new DecimalFormat("##0E0").format(number);
    r = r.replaceAll("E[0-9]", suffix[Character.getNumericValue(r.charAt(r.length() - 1)) / 3]);
    while(r.length() > MAX_LENGTH || r.matches("[0-9]+\\.[a-z]")){
        r = r.substring(0, r.length()-2) + r.substring(r.length() - 1);
    }
    return r;
}

আউটপুট:

7 = 7
12 = 12
856 = 856
1000 = 1k
5821 = 5.8k
10500 = 10k
101800 = 102k
2000000 = 2m
7800000 = 7.8m
92150000 = 92m
123200000 = 123m
9999999 = 10m

@ ম্যাট নতুন প্রয়োজনীয়তাগুলি পরিচালনা করতে আপডেট হয়েছে
জেডডি

মুদ্রার সাথে অনুরূপ কার্যকারিতা পেতে কি মুদ্রা ইনস্ট্যান্সের সাথে এটি একত্রিত করার সহজ উপায় আছে?
এক্সডুমাইন

@ আরভিউজার, আপনার অর্থ কী তা নিশ্চিত নন তবে এটি একটি পৃথক প্রশ্নের মতো মনে হচ্ছে।
জেডডি

7
160000 থেকে
200

4
এটি ভেঙে গেছে, আমি 10000000000000000.0 নম্বরে প্রবেশ করেছি এবং এটি 103 বলছে
অলিভার ডিকসন

23

কিছু উন্নতি প্রয়োজন, কিন্তু: স্ট্রাইকমেথ রেসকিউ!
আপনি একটি স্ট্রিং বা অ্যারেতে প্রত্যয় স্থাপন করতে পারেন এবং পাওয়ার বা এমন কিছুর উপর ভিত্তি করে আনতে পারেন।
বিভাগটি বিদ্যুতের চারপাশেও পরিচালিত হতে পারে, আমার মনে হয় প্রায় সবকিছুই পাওয়ার মান সম্পর্কে। আশা করি এটা সাহায্য করবে!

public static String formatValue(double value) {
int power; 
    String suffix = " kmbt";
    String formattedNumber = "";

    NumberFormat formatter = new DecimalFormat("#,###.#");
    power = (int)StrictMath.log10(value);
    value = value/(Math.pow(10,(power/3)*3));
    formattedNumber=formatter.format(value);
    formattedNumber = formattedNumber + suffix.charAt(power/3);
    return formattedNumber.length()>4 ?  formattedNumber.replaceAll("\\.[0-9]+", "") : formattedNumber;  
}

আউটপুট:

999
1.2 কে
98 কে
911 কে
1.1 মি
11 বি
712 বি 34
টি


2
কিছুটা পঠনযোগ্যতা কিছুটা উন্নত হয়েছে, চারটি সমস্যা সমাধানের জন্য জেজেডি থেকে রিটার্ন স্টেটমেন্ট যুক্ত করা দরকার। এবং এআইইউওবি ব্যতিক্রম এড়ানোর জন্য টিয়ের বেশি হলে প্রত্যয় যুক্ত মনে রাখবেন। ;)
ঝুরতুদো

এই কোডটি লোকেলের প্রতি সংবেদনশীল, উদাহরণস্বরূপ, এসভি_এসই লোকালে 1000 10x10³ এ রূপান্তর করে, যা সঠিকভাবে রেজিপেক্সের সাথে মেলে না।
জোয়াকিম লুন্ডবার্গ

2
0 এর জন্য একটি ব্যতিক্রম ছুঁড়ে, negativeণাত্মক সংখ্যার জন্য কাজ করে না, 9,999,999 সঠিকভাবে গোল করে না (10 মি প্রিন্ট করে) ...
অ্যাসিরিয়াস

16

বর্তমান উত্তরগুলির সাথে সমস্যা

  • বর্তমানের অনেকগুলি সমাধান এই উপসর্গগুলি কে = 10 3 , এম = 10 6 , বি = 10 9 , টি = 10 12 ব্যবহার করছে । তবে বিভিন্ন উত্স অনুসারে সঠিক উপসর্গগুলি হল কে = 10 3 , এম = 10 6 , জি = 10 9 , টি = 10 12
  • Negativeণাত্মক সংখ্যার জন্য সমর্থনের অভাব (বা কমপক্ষে পরীক্ষার অভাব যে প্রদর্শন করে যে নেতিবাচক সংখ্যাগুলি সমর্থিত)
  • বিপরীত ক্রিয়াকলাপের জন্য সমর্থনের অভাব, উদাহরণস্বরূপ, 1.1 কে 1100 এ রূপান্তর করা (যদিও এটি মূল প্রশ্নের ক্ষেত্রের বাইরে)

জাভা সলিউশন

এই সমাধান ( এই উত্তরের একটি এক্সটেনশন ) উপরের সমস্যাগুলিকে সম্বোধন করে।

import org.apache.commons.lang.math.NumberUtils;

import java.text.DecimalFormat;
import java.text.FieldPosition;
import java.text.Format;
import java.text.ParsePosition;
import java.util.regex.Pattern;


/**
 * Converts a number to a string in <a href="http://en.wikipedia.org/wiki/Metric_prefix">metric prefix</a> format.
 * For example, 7800000 will be formatted as '7.8M'. Numbers under 1000 will be unchanged. Refer to the tests for further examples.
 */
class RoundedMetricPrefixFormat extends Format {

    private static final String[] METRIC_PREFIXES = new String[]{"", "k", "M", "G", "T"};

    /**
     * The maximum number of characters in the output, excluding the negative sign
     */
    private static final Integer MAX_LENGTH = 4;

    private static final Pattern TRAILING_DECIMAL_POINT = Pattern.compile("[0-9]+\\.[kMGT]");

    private static final Pattern METRIC_PREFIXED_NUMBER = Pattern.compile("\\-?[0-9]+(\\.[0-9])?[kMGT]");

    @Override
    public StringBuffer format(Object obj, StringBuffer output, FieldPosition pos) {

        Double number = Double.valueOf(obj.toString());

        // if the number is negative, convert it to a positive number and add the minus sign to the output at the end
        boolean isNegative = number < 0;
        number = Math.abs(number);

        String result = new DecimalFormat("##0E0").format(number);

        Integer index = Character.getNumericValue(result.charAt(result.length() - 1)) / 3;
        result = result.replaceAll("E[0-9]", METRIC_PREFIXES[index]);

        while (result.length() > MAX_LENGTH || TRAILING_DECIMAL_POINT.matcher(result).matches()) {
            int length = result.length();
            result = result.substring(0, length - 2) + result.substring(length - 1);
        }

        return output.append(isNegative ? "-" + result : result);
    }

    /**
     * Convert a String produced by <tt>format()</tt> back to a number. This will generally not restore
     * the original number because <tt>format()</tt> is a lossy operation, e.g.
     *
     * <pre>
     * {@code
     * def formatter = new RoundedMetricPrefixFormat()
     * Long number = 5821L
     * String formattedNumber = formatter.format(number)
     * assert formattedNumber == '5.8k'
     *
     * Long parsedNumber = formatter.parseObject(formattedNumber)
     * assert parsedNumber == 5800
     * assert parsedNumber != number
     * }
     * </pre>
     *
     * @param source a number that may have a metric prefix
     * @param pos if parsing succeeds, this should be updated to the index after the last parsed character
     * @return a Number if the the string is a number without a metric prefix, or a Long if it has a metric prefix
     */
    @Override
    public Object parseObject(String source, ParsePosition pos) {

        if (NumberUtils.isNumber(source)) {

            // if the value is a number (without a prefix) don't return it as a Long or we'll lose any decimals
            pos.setIndex(source.length());
            return toNumber(source);

        } else if (METRIC_PREFIXED_NUMBER.matcher(source).matches()) {

            boolean isNegative = source.charAt(0) == '-';
            int length = source.length();

            String number = isNegative ? source.substring(1, length - 1) : source.substring(0, length - 1);
            String metricPrefix = Character.toString(source.charAt(length - 1));

            Number absoluteNumber = toNumber(number);

            int index = 0;

            for (; index < METRIC_PREFIXES.length; index++) {
                if (METRIC_PREFIXES[index].equals(metricPrefix)) {
                    break;
                }
            }

            Integer exponent = 3 * index;
            Double factor = Math.pow(10, exponent);
            factor *= isNegative ? -1 : 1;

            pos.setIndex(source.length());
            Float result = absoluteNumber.floatValue() * factor.longValue();
            return result.longValue();
        }

        return null;
    }

    private static Number toNumber(String number) {
        return NumberUtils.createNumber(number);
    }
}

গ্রোভি সলিউশন

সমাধানটি নীচে দেখানো হিসাবে গ্রোভিতে মূলত লেখা হয়েছিল।

import org.apache.commons.lang.math.NumberUtils

import java.text.DecimalFormat
import java.text.FieldPosition
import java.text.Format
import java.text.ParsePosition
import java.util.regex.Pattern


/**
 * Converts a number to a string in <a href="http://en.wikipedia.org/wiki/Metric_prefix">metric prefix</a> format.
 * For example, 7800000 will be formatted as '7.8M'. Numbers under 1000 will be unchanged. Refer to the tests for further examples.
 */
class RoundedMetricPrefixFormat extends Format {

    private static final METRIC_PREFIXES = ["", "k", "M", "G", "T"]

    /**
     * The maximum number of characters in the output, excluding the negative sign
     */
    private static final Integer MAX_LENGTH = 4

    private static final Pattern TRAILING_DECIMAL_POINT = ~/[0-9]+\.[kMGT]/

    private static final Pattern METRIC_PREFIXED_NUMBER = ~/\-?[0-9]+(\.[0-9])?[kMGT]/

    @Override
    StringBuffer format(Object obj, StringBuffer output, FieldPosition pos) {

        Double number = obj as Double

        // if the number is negative, convert it to a positive number and add the minus sign to the output at the end
        boolean isNegative = number < 0
        number = Math.abs(number)

        String result = new DecimalFormat("##0E0").format(number)

        Integer index = Character.getNumericValue(result.charAt(result.size() - 1)) / 3
        result = result.replaceAll("E[0-9]", METRIC_PREFIXES[index])

        while (result.size() > MAX_LENGTH || TRAILING_DECIMAL_POINT.matcher(result).matches()) {
            int length = result.size()
            result = result.substring(0, length - 2) + result.substring(length - 1)
        }

        output << (isNegative ? "-$result" : result)
    }

    /**
     * Convert a String produced by <tt>format()</tt> back to a number. This will generally not restore
     * the original number because <tt>format()</tt> is a lossy operation, e.g.
     *
     * <pre>
     * {@code
     * def formatter = new RoundedMetricPrefixFormat()
     * Long number = 5821L
     * String formattedNumber = formatter.format(number)
     * assert formattedNumber == '5.8k'
     *
     * Long parsedNumber = formatter.parseObject(formattedNumber)
     * assert parsedNumber == 5800
     * assert parsedNumber != number
     * }
     * </pre>
     *
     * @param source a number that may have a metric prefix
     * @param pos if parsing succeeds, this should be updated to the index after the last parsed character
     * @return a Number if the the string is a number without a metric prefix, or a Long if it has a metric prefix
     */
    @Override
    Object parseObject(String source, ParsePosition pos) {

        if (source.isNumber()) {

            // if the value is a number (without a prefix) don't return it as a Long or we'll lose any decimals
            pos.index = source.size()
            toNumber(source)

        } else if (METRIC_PREFIXED_NUMBER.matcher(source).matches()) {

            boolean isNegative = source[0] == '-'

            String number = isNegative ? source[1..-2] : source[0..-2]
            String metricPrefix = source[-1]

            Number absoluteNumber = toNumber(number)

            Integer exponent = 3 * METRIC_PREFIXES.indexOf(metricPrefix)
            Long factor = 10 ** exponent
            factor *= isNegative ? -1 : 1

            pos.index = source.size()
            (absoluteNumber * factor) as Long
        }
    }

    private static Number toNumber(String number) {
        NumberUtils.createNumber(number)
    }
}

পরীক্ষা (গ্রোভি)

পরীক্ষাগুলি গ্রোভিতে লেখা রয়েছে তবে জাভা বা গ্রোভির ক্লাস হয় হয় তা যাচাই করতে ব্যবহার করা যেতে পারে (কারণ তাদের উভয়টিরই নাম এবং এপিআই রয়েছে)।

import java.text.Format
import java.text.ParseException

class RoundedMetricPrefixFormatTests extends GroovyTestCase {

    private Format roundedMetricPrefixFormat = new RoundedMetricPrefixFormat()

    void testNumberFormatting() {

        [
                7L         : '7',
                12L        : '12',
                856L       : '856',
                1000L      : '1k',
                (-1000L)   : '-1k',
                5821L      : '5.8k',
                10500L     : '10k',
                101800L    : '102k',
                2000000L   : '2M',
                7800000L   : '7.8M',
                (-7800000L): '-7.8M',
                92150000L  : '92M',
                123200000L : '123M',
                9999999L   : '10M',
                (-9999999L): '-10M'
        ].each { Long rawValue, String expectedRoundValue ->

            assertEquals expectedRoundValue, roundedMetricPrefixFormat.format(rawValue)
        }
    }

    void testStringParsingSuccess() {
        [
                '7'    : 7,
                '8.2'  : 8.2F,
                '856'  : 856,
                '-856' : -856,
                '1k'   : 1000,
                '5.8k' : 5800,
                '-5.8k': -5800,
                '10k'  : 10000,
                '102k' : 102000,
                '2M'   : 2000000,
                '7.8M' : 7800000L,
                '92M'  : 92000000L,
                '-92M' : -92000000L,
                '123M' : 123000000L,
                '10M'  : 10000000L

        ].each { String metricPrefixNumber, Number expectedValue ->

            def parsedNumber = roundedMetricPrefixFormat.parseObject(metricPrefixNumber)
            assertEquals expectedValue, parsedNumber
        }
    }

    void testStringParsingFail() {

        shouldFail(ParseException) {
            roundedMetricPrefixFormat.parseObject('notNumber')
        }
    }
}

1
আমি মনে করি আপনি সিএস উপসর্গ সম্পর্কে চিন্তা করছেন, প্রদত্ত যে তিনি কোটি কোটি এবং ট্রিলিয়ন সম্পর্কে কথা বলছেন বলে আমি অনুমান করি যে তিনি স্বল্প স্কেল সংখ্যার চান।
ঝুরতাডো

1
9999999 এর 9.9 মি হিসাবে মুদ্রণ করা উচিত আমার বিশ্বাস (সংখ্যাগুলি কেটে ফেলা হয়, গোল হয় না)।
Assylias

এই দ্রবণটির 1 টির চেয়ে কম মানের, যেমন ইউ (মাইক্রো) এবং এম (মিলি) এর উপসর্গগুলির জন্য সমর্থন নেই।
gbmhunter

13

আইসিইউ liberal এর সংক্ষিপ্ত রূপ সংখ্যার জন্য একটি নিয়ম ভিত্তিক ফরম্যাটার, যা সংখ্যা spellout ইত্যাদি আমি ব্যবহার করা যেতে পারে ব্যবহার মনে আইসিইউ আপনি একটি পাঠযোগ্য এবং maintanable সমাধান দিতে হবে না।

[ব্যবহারের]

ডান ক্লাসটি রুলবেসডনম্বার ফর্ম্যাট। ফর্ম্যাটটি পৃথক ফাইল হিসাবে সংরক্ষণ করা যেতে পারে (বা স্ট্রিং ধ্রুবক হিসাবে, আইআইআরসি)।

থেকে উদাহরণ http://userguide.icu-project.org/formatparse/numbers

double num = 2718.28;
NumberFormat formatter = 
    new RuleBasedNumberFormat(RuleBasedNumberFormat.SPELLOUT);
String result = formatter.format(num);
System.out.println(result);

একই পৃষ্ঠাটিতে রোমান সংখ্যা দেখানো হয়েছে, সুতরাং আমার ধারণা আপনার ক্ষেত্রেও এটি সম্ভব হওয়া উচিত।


থ্রেডের একমাত্র সমাধান যা আপনার স্থানীয়করণের প্রয়োজন হলে সম্পূর্ণ বিচ্ছিন্ন হয় না।
গ্রোজ

2
অ্যান্ড্রয়েড বিকাশের জন্য আপনার যদি এটির প্রয়োজন হয় তবে এটি ইতিমধ্যে কাঠামোর মধ্যে অন্তর্ভুক্ত রয়েছে। জন্য দেখুন CompactDecimalFormat। এপিআই স্তর 24+
গোখন আরিক

10

সঙ্গে জাভা-12 + + , আপনি ব্যবহার করতে পারেন NumberFormat.getCompactNumberInstanceসংখ্যার ফরম্যাট করতে। আপনি NumberFormatপ্রথম হিসাবে তৈরি করতে পারেন

NumberFormat fmt = NumberFormat.getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT);

এবং তারপরে এটি ব্যবহার করুন format:

fmt.format(1000)
$5 ==> "1K"

fmt.format(10000000)
$9 ==> "10M"

fmt.format(1000000000)
$11 ==> "1B"

8

গুরুত্বপূর্ণ: উত্তর দেওয়ার doubleজন্য উত্তরগুলি ব্যর্থ হবে 99999999999999999Lএবং 100Pপরিবর্তে ফিরে আসবে 99Pকারণ মানটিdouble ব্যবহার করে :IEEE

যদি সর্বাধিক 15 উল্লেখযোগ্য সংখ্যার দশমিক স্ট্রিং আইইইই 754 ডাবল স্পষ্টতা উপস্থাপনায় রূপান্তরিত হয় এবং তারপরে একই সংখ্যক উল্লেখযোগ্য অঙ্কের সাথে একটি স্ট্রিংয়ে ফিরে রূপান্তরিত হয়, তবে চূড়ান্ত স্ট্রিংটি মূলটির সাথে মেলে। [ longগেছে পর্যন্ত 19 এতগুলি অর্থপূর্ণ অঙ্ক ।]

System.out.println((long)(double)99999999999999992L); // 100000000000000000
System.out.println((long)(double)99999999999999991L); //  99999999999999984
// it is even worse for the logarithm:
System.out.println(Math.log10(99999999999999600L)); // 17.0
System.out.println(Math.log10(99999999999999500L)); // 16.999999999999996

এই সমাধানটি অযাচিত সংখ্যাগুলি কেটে দেয় এবং সমস্ত longমানগুলির জন্য কাজ করে । সাধারণ তবে পারফরম্যান্ট বাস্তবায়ন (নীচে তুলনা)। -120k 4 টি অক্ষর দিয়ে প্রকাশ করা যায় না, এমনকি -0.1M খুব দীর্ঘ, তাই negativeণাত্মক সংখ্যার জন্য 5 টি অক্ষর ঠিক আছে:

private static final char[] magnitudes = {'k', 'M', 'G', 'T', 'P', 'E'}; // enough for long

public static final String convert(long number) {
    String ret;
    if (number >= 0) {
        ret = "";
    } else if (number <= -9200000000000000000L) {
        return "-9.2E";
    } else {
        ret = "-";
        number = -number;
    }
    if (number < 1000)
        return ret + number;
    for (int i = 0; ; i++) {
        if (number < 10000 && number % 1000 >= 100)
            return ret + (number / 1000) + '.' + ((number % 1000) / 100) + magnitudes[i];
        number /= 1000;
        if (number < 1000)
            return ret + number + magnitudes[i];
    }
}

পরীক্ষা else ifকারণ মিনিট শুরুতে necessairy হয় -(2^63)এবং সর্বোচ্চ (2^63)-1এবং সেইজন্য নিয়োগ number = -numberব্যর্থ হবে যদি number == Long.MIN_VALUE। যদি আমাদের একটি চেক করতে হয়, তবে আমরা কেবলমাত্র পরীক্ষার পরিবর্তে যতগুলি সম্ভব সংখ্যক অন্তর্ভুক্ত করতে পারিnumber == Long.MIN_VALUE

যিনি সর্বাধিক উন্নতি পেয়েছিলেন (বর্তমানে সবচেয়ে দ্রুত বলেছিলেন) তার সাথে এই বাস্তবায়নটির তুলনা দেখিয়েছে যে এটি 5 গুণ বেশি দ্রুত (এটি পরীক্ষার সেটিংসের উপর নির্ভর করে, তবে আরও সংখ্যার সাহায্যে লাভটি আরও বড় হয় এবং এই বাস্তবায়ন হয়েছে) আরও চেক করতে হবে কারণ এটি সমস্ত ক্ষেত্রে পরিচালনা করে, সুতরাং অন্যটি স্থির করা হলে পার্থক্যটি আরও বড় হয়ে উঠবে)। এটি এত দ্রুত যেহেতু কোনও ভাসমান পয়েন্ট অপারেশন নেই, লোগারিদম নেই, শক্তি নেই, কোন পুনরাবৃত্তি নেই, কোনও রেজেক্স নেই, কোনও পরিশীলিত বিন্যাস নেই এবং তৈরি বস্তুর পরিমাণকে হ্রাস করতে পারে না।


টেস্ট প্রোগ্রামটি এখানে:

public class Test {

    public static void main(String[] args) {
        long[] numbers = new long[20000000];
        for (int i = 0; i < numbers.length; i++)
            numbers[i] = Math.random() < 0.5 ? (long) (Math.random() * Long.MAX_VALUE) : (long) (Math.random() * Long.MIN_VALUE);
        System.out.println(convert1(numbers) + " vs. " + convert2(numbers));
    }

    private static long convert1(long[] numbers) {
        long l = System.currentTimeMillis();
        for (int i = 0; i < numbers.length; i++)
            Converter1.convert(numbers[i]);
        return System.currentTimeMillis() - l;
    }

    private static long convert2(long[] numbers) {
        long l = System.currentTimeMillis();
        for (int i = 0; i < numbers.length; i++)
            Converter2.coolFormat(numbers[i], 0);
        return System.currentTimeMillis() - l;
    }

}

সম্ভাব্য আউটপুট: 2309 vs. 11591(একই মাত্র যখন ইতিবাচক সংখ্যাগুলি ব্যবহার করে এবং কার্যকর করার ক্রমকে বিপরীত করার সময় আরও চরম, সম্ভবত আবর্জনা সংগ্রহের সাথে এর কিছু যুক্ত রয়েছে)


8

এখানে পুনরাবৃত্তি ছাড়াই একটি সংক্ষিপ্ত বাস্তবায়ন এবং কেবল একটি খুব ছোট লুপ। নেতিবাচক সংখ্যা নিয়ে কাজ করে না তবে সমস্ত ধনাত্মক longটি পর্যন্ত সমর্থন করে Long.MAX_VALUE:

private static final char[] SUFFIXES = {'k', 'm', 'g', 't', 'p', 'e' };

public static String format(long number) {
    if(number < 1000) {
        // No need to format this
        return String.valueOf(number);
    }
    // Convert to a string
    final String string = String.valueOf(number);
    // The suffix we're using, 1-based
    final int magnitude = (string.length() - 1) / 3;
    // The number of digits we must show before the prefix
    final int digits = (string.length() - 1) % 3 + 1;

    // Build the string
    char[] value = new char[4];
    for(int i = 0; i < digits; i++) {
        value[i] = string.charAt(i);
    }
    int valueLength = digits;
    // Can and should we add a decimal point and an additional number?
    if(digits == 1 && string.charAt(1) != '0') {
        value[valueLength++] = '.';
        value[valueLength++] = string.charAt(1);
    }
    value[valueLength++] = SUFFIXES[magnitude - 1];
    return new String(value, 0, valueLength);
}

আউটপুট:

1k
5.8k
10k
101k
2m
7.8m
92m
123m
9.2e (এই হল Long.MAX_VALUE)

আমি কিছু সহজ সরল বেঞ্চমার্কিংও করেছি (১০০ মিলিয়ন এলোমেলো দীর্ঘ বিন্যাস) এবং এটি এলিয়াহর বাস্তবায়নের চেয়ে যথেষ্ট দ্রুত এবং অ্যাসিলিয়াসের প্রয়োগের চেয়ে কিছুটা দ্রুত faster

খনি: 1137.028 এমএস
এলিয়াসের: 2664.396 এমএস
অ্যাসিলিয়া ': 1373.473 এমএস


1
আপনার শেষ আপডেটে, আপনি একটি বাগ যুক্ত করেছেন। এটি এখন 101800 নম্বরের জন্য 1k প্রদান করে ।
সুফিয়ান

2
লক্ষ্য করার জন্য ধন্যবাদ, এটি ঠিক হয়েছে
রানিজ

8

যে কেউ গোল করতে চায়। এটি জাভা.ল্যাং.মথ লাইব্রেরির সুবিধা নেয় এটি একটি দুর্দান্ত, সহজেই পড়ার সমাধান

 public static String formatNumberExample(Number number) {
        char[] suffix = {' ', 'k', 'M', 'B', 'T', 'P', 'E'};
        long numValue = number.longValue();
        int value = (int) Math.floor(Math.log10(numValue));
        int base = value / 3;
        if (value >= 3 && base < suffix.length) {
            return new DecimalFormat("~#0.0").format(numValue / Math.pow(10, base * 3)) + suffix[base];
        } else {
            return new DecimalFormat("#,##0").format(numValue);
        }
    }

8

নীচের কোডটি দেখায় যে আপনি কীভাবে সহজ প্রসারকে সামনে রেখে এটি করতে পারেন।

"যাদু" বেশিরভাগ ক্ষেত্রেই থাকে makeDecimal থাকে যা সঠিক মানগুলির জন্য পাস করে, গ্যারান্টি দেয় যে আপনার আউটপুটে চারটি অক্ষরের বেশি কখনও থাকবে না।

এটি প্রথমে প্রদত্ত বিভাজকের জন্য পুরো এবং দশম অংশটি নিষ্কাশন করে, উদাহরণস্বরূপ, 12,345,678একটি বিভাজকের সাথে 1,000,000একটি wholeমান 12এবং একটি tenthsমান দেবে 3

সেখান থেকে, এটি সিদ্ধান্ত নিতে পারে যে এটি নিয়মগুলি ব্যবহার করে কেবল পুরো অংশ বা পুরো এবং দশম অংশ উভয়ই আউটপুট দেয়:

  • দশমীর অংশটি যদি শূন্য হয় তবে কেবল পুরো অংশ এবং প্রত্যয় আউটপুট করুন।
  • যদি পুরো অংশটি নয়টির বেশি হয় তবে কেবল পুরো অংশ এবং প্রত্যয় আউটপুট করুন।
  • অন্যথায়, আউটপুট পুরো অংশ, দশম অংশ এবং প্রত্যয়।

তার জন্য কোডটি নিম্নলিখিত:

static private String makeDecimal(long val, long div, String sfx) {
    val = val / (div / 10);
    long whole = val / 10;
    long tenths = val % 10;
    if ((tenths == 0) || (whole >= 10))
        return String.format("%d%s", whole, sfx);
    return String.format("%d.%d%s", whole, tenths, sfx);
}

তারপরে, বিকাশকারীর পক্ষে জীবন সহজ করার জন্য কিছু ধ্রুবক সহ সঠিক মূল্যবোধ সহ সেই সহায়কটিকে ফাংশন বলা সহজ বিষয়:

static final long THOU =                1000L;
static final long MILL =             1000000L;
static final long BILL =          1000000000L;
static final long TRIL =       1000000000000L;
static final long QUAD =    1000000000000000L;
static final long QUIN = 1000000000000000000L;

static private String Xlat(long val) {
    if (val < THOU) return Long.toString(val);
    if (val < MILL) return makeDecimal(val, THOU, "k");
    if (val < BILL) return makeDecimal(val, MILL, "m");
    if (val < TRIL) return makeDecimal(val, BILL, "b");
    if (val < QUAD) return makeDecimal(val, TRIL, "t");
    if (val < QUIN) return makeDecimal(val, QUAD, "q");
    return makeDecimal(val, QUIN, "u");
}

এই makeDecimalফাংশনটি উদ্বেগজনক কাজটি করার অর্থ এই যে এর বাইরে প্রসারিত 999,999,999করা কেবলমাত্র একটি অতিরিক্ত লাইন যুক্ত করার বিষয় Xlat, এত সহজ যে আমি এটি আপনার জন্য করেছি।

চূড়ান্ত returnমধ্যে Xlatএকটি শর্তাধীন দরকার নেই যেহেতু বৃহত্তম মান আপনি যদি একটি 64-বিট দীর্ঘ স্বাক্ষর মধ্যে ধরে রাখতে পারেন শুধুমাত্র 9.2 দশ লক্ষের পঞ্চঘাত সম্পর্কে।

তবে, যদি কিছু উদ্ভট প্রয়োজন অনুসারে ওরাকল একটি 128-বিট longerটাইপ বা 1024-বিট damn_longটাইপ যুক্ত করার সিদ্ধান্ত নেয় , আপনি তার জন্য প্রস্তুত হবেন :-)


এবং, অবশেষে, কার্যকারিতা যাচাই করার জন্য আপনি একটি সামান্য পরীক্ষার জোতা ব্যবহার করতে পারেন।

public static void main(String[] args) {
    long vals[] = {
        999L, 1000L, 5821L, 10500L, 101800L, 2000000L,
        7800000L, 92150000L, 123200000L, 999999999L,
        1000000000L, 1100000000L, 999999999999L,
        1000000000000L, 999999999999999L,
        1000000000000000L, 9223372036854775807L
    };
    for (long val: vals)
        System.out.println ("" + val + " -> " + Xlat(val));
    }
}

আপনি আউটপুট থেকে দেখতে পাচ্ছেন যে এটি আপনাকে যা প্রয়োজন তা দেয়:

999 -> 999
1000 -> 1k
5821 -> 5.8k
10500 -> 10k
101800 -> 101k
2000000 -> 2m
7800000 -> 7.8m
92150000 -> 92m
123200000 -> 123m
999999999 -> 999m
1000000000 -> 1b
1100000000 -> 1.1b
999999999999 -> 999b
1000000000000 -> 1t
999999999999999 -> 999t
1000000000000000 -> 1q
9223372036854775807 -> 9.2u

এবং, একদিকে যেমন সচেতন থাকবেন যে এই ফাংশনে নেতিবাচক সংখ্যায় উত্তীর্ণ হওয়ার ফলে আপনার প্রয়োজনীয়তার জন্য একটি স্ট্রিং খুব দীর্ঘ হবে, যেহেতু এটি অনুসরণ করে < THOU)। আমি অনুভব করেছি যে এটি ঠিক আছে কারণ আপনি কেবল প্রশ্নে অ-নেতিবাচক মানগুলি উল্লেখ করেন values


6

আমি জানি না এটি সর্বোত্তম পন্থা কিনা তবে, আমি এটিই করেছি।

7=>7
12=>12
856=>856
1000=>1.0k
5821=>5.82k
10500=>10.5k
101800=>101.8k
2000000=>2.0m
7800000=>7.8m
92150000=>92.15m
123200000=>123.2m
9999999=>10.0m

--- কোড ---

public String Format(Integer number){
    String[] suffix = new String[]{"k","m","b","t"};
    int size = (number.intValue() != 0) ? (int) Math.log10(number) : 0;
    if (size >= 3){
        while (size % 3 != 0) {
            size = size - 1;
        }
    }
    double notation = Math.pow(10, size);
    String result = (size >= 3) ? + (Math.round((number / notation) * 100) / 100.0d)+suffix[(size/3) - 1] : + number + "";
    return result
}

6

বড় সংখ্যাটিকে ছোট সংখ্যায় রূপান্তর করার জন্য আমার কার্য (2 অঙ্ক সহ)। আপনি পরিবর্তন দ্বারা ডিজিটের সংখ্যা পরিবর্তন করতে পারেন #.##মধ্যেDecimalFormat

public String formatValue(float value) {
    String arr[] = {"", "K", "M", "B", "T", "P", "E"};
    int index = 0;
    while ((value / 1000) >= 1) {
        value = value / 1000;
        index++;
    }
    DecimalFormat decimalFormat = new DecimalFormat("#.##");
    return String.format("%s %s", decimalFormat.format(value), arr[index]);
}

পরীক্ষামূলক

System.out.println(formatValue(100));     //  100
System.out.println(formatValue(1000));    // 1 K
System.out.println(formatValue(10345));   // 10.35 K
System.out.println(formatValue(10012));   // 10.01 K
System.out.println(formatValue(123456));  // 123.46 K
System.out.println(formatValue(4384324)); // 4.38 M
System.out.println(formatValue(10000000)); // 10 M
System.out.println(formatValue(Long.MAX_VALUE)); // 9.22 E

আশা করি এটি সাহায্য করবে


5

আমার জাভাটি মরিচা, তবে আমি সি # তে এটি কীভাবে প্রয়োগ করব:

private string  FormatNumber(double value)
    {
    string[]  suffixes = new string[] {" k", " m", " b", " t", " q"};
    for (int j = suffixes.Length;  j > 0;  j--)
        {
        double  unit = Math.Pow(1000, j);
        if (value >= unit)
            return (value / unit).ToString("#,##0.0") + suffixes[--j];
        }
    return value.ToString("#,##0");
    }

মেট্রিক কিলোর চেয়ে সিএস কিলো (1,024) ব্যবহার করতে বা আরও ইউনিট যুক্ত করার জন্য এটি সামঞ্জস্য করা সহজ হবে। এটি "1 কে" এর পরিবর্তে 1,000 কে "1.0 কে" হিসাবে ফর্ম্যাট করে তবে আমি বিশ্বাস করি যে এটি অবিরাম।

"চারটি অক্ষরের বেশি নয়" সুনির্দিষ্ট প্রয়োজনীয়তা পূরণের জন্য প্রত্যয়গুলির আগে স্পেসগুলি সরিয়ে ফেলুন এবং মাঝের ব্লকটি এভাবে সামঞ্জস্য করুন:

if (value >= unit)
  {
  value /= unit;
  return (value).ToString(value >= unit * 9.95 ? "#,##0" : "#,##0.0") + suffixes[--j];
  }

1
দুর্ভাগ্যক্রমে ToStringজাভাতে এই পদ্ধতিটির অস্তিত্ব নেই - আপনার একটি নম্বর ফর্ম্যাট লাগবে যা অন্যান্য সমস্যা তৈরি করতে পারে (স্থানীয় সংবেদনশীল ইত্যাদি)।
Assylias

5

আমার পছন্দ. আপনি ইলেক্ট্রনিক ডোমেইনে সাধারণ হিসাবে দশমিকের জন্য সূচক হিসাবে "কে" ব্যবহার করতে পারেন। এটি আপনাকে অতিরিক্ত স্থান ছাড়াই একটি অতিরিক্ত অঙ্ক দেবে

দ্বিতীয় কলাম যথাসম্ভব অঙ্ক ব্যবহার করার চেষ্টা করে

1000 => 1.0k | 1000
5821 => 5.8k | 5821
10500 => 10k | 10k5
101800 => 101k | 101k
2000000 => 2.0m | 2m
7800000 => 7.8m | 7m8
92150000 => 92m | 92m1
123200000 => 123m | 123m
9999999 => 9.9m | 9m99

এই কোড

public class HTTest {
private static String[] unit = {"u", "k", "m", "g", "t"};
/**
 * @param args
 */
public static void main(String[] args) {
    int[] numbers = new int[]{1000, 5821, 10500, 101800, 2000000, 7800000, 92150000, 123200000, 9999999};
    for(int n : numbers) {
        System.out.println(n + " => " + myFormat(n) + " | " + myFormat2(n));
    }
}

private static String myFormat(int pN) {
    String str = Integer.toString(pN);
    int len = str.length ()-1;
    if (len <= 3) return str;
    int level = len / 3;
    int mode = len % 3;
    switch (mode) {
    case 0: return str.substring(0, 1) + "." + str.substring(1, 2) + unit[level];
    case 1: return str.substring(0, 2) + unit[level];
    case 2: return str.substring(0, 3) + unit[level];
    }
    return "how that?";
}
private static String trim1 (String pVal) {
    if (pVal.equals("0")) return "";
    return pVal;
}
private static String trim2 (String pVal) {
    if (pVal.equals("00")) return "";
    return pVal.substring(0, 1) + trim1(pVal.substring(1,2));
}
private static String myFormat2(int pN) {
    String str = Integer.toString(pN);
    int len = str.length () - 1;
    if (len <= 3) return str;
    int level = len / 3;
    int mode = len % 3;
    switch (mode) {
    case 0: return str.substring(0, 1) + unit[level] + trim2(str.substring(1, 3));
    case 2: return str.substring(0, 3) + unit[level];
    case 1: return str.substring(0, 2) + unit[level] + trim1(str.substring(2, 3));
    }
    return "how that?";
}
}

4

আমার এই মন্তব্যে সত্যতা অবলম্বন করে যে আমি পারফরম্যান্সের উপরের পাঠযোগ্যতার মূল্য দিতে চাই, এখানে এমন একটি সংস্করণ রয়েছে যেখানে এটি স্পষ্ট হওয়া উচিত যা ঘটছে তা (ধরে নিই যে আপনি ব্যবহার করেছেন BigDecimal অত্যধিক মন্তব্য না করে (আমি স্ব-ডকুমেন্টিং কোডে বিশ্বাস করি) এটি আগে হয়েছে) (যেহেতু আমি এমন কোনও দৃশ্যের চিত্র তুলতে পারি না যেখানে আপনি এত লক্ষ লক্ষ বার করতে চান যে পারফরম্যান্স এমনকি বিবেচ্য হয়ে ওঠে)।

এই সংস্করণ:

  • ব্যবহারসমূহ BigDecimalস্পষ্টতা এবং এড়ানোর rounding সমস্যার গুলি
  • ওপির অনুরোধ অনুসারে গোল করার জন্য কাজ করে
  • অন্যান্য বৃত্তাকার মোডের জন্য কাজ করে, যেমন HALF_UPপরীক্ষাগুলির মতো
  • আপনি নির্ভুলতা পরিবর্তন করতে পারবেন (পরিবর্তন REQUIRED_PRECISION)
  • enumপ্রান্তিক সংজ্ঞা নির্ধারণ করতে একটি ব্যবহার করে , সহজেই কে / এম / বি / টি, ইত্যাদির পরিবর্তে কেবি / এমবি / জিবি / টিবি ব্যবহার করতে সামঞ্জস্য করা যেতে পারে এবং অবশ্যই এর বাইরেও প্রসারিত হতে পারেTRILLION যদি প্রয়োজন
  • প্রশ্নে পরীক্ষার কেসগুলি সীমানা পরীক্ষা করছিল না বলে পুরো ইউনিট পরীক্ষা নিয়ে আসে
  • শূন্য এবং নেতিবাচক সংখ্যার জন্য কাজ করা উচিত

থ্রেশহোল্ড.জভা :

import java.math.BigDecimal;

public enum Threshold {
  TRILLION("1000000000000", 12, 't', null),
  BILLION("1000000000", 9, 'b', TRILLION),
  MILLION("1000000", 6, 'm', BILLION),
  THOUSAND("1000", 3, 'k', MILLION),
  ZERO("0", 0, null, THOUSAND);

  private BigDecimal value;
  private int zeroes;
  protected Character suffix;
  private Threshold higherThreshold;

  private Threshold(String aValueString, int aNumberOfZeroes, Character aSuffix,
      Threshold aThreshold) {
    value = new BigDecimal(aValueString);
    zeroes = aNumberOfZeroes;
    suffix = aSuffix;
    higherThreshold = aThreshold;
  }

  public static Threshold thresholdFor(long aValue) {
    return thresholdFor(new BigDecimal(aValue));
  }

  public static Threshold thresholdFor(BigDecimal aValue) {
    for (Threshold eachThreshold : Threshold.values()) {
      if (eachThreshold.value.compareTo(aValue) <= 0) {
        return eachThreshold;
      }
    }
    return TRILLION; // shouldn't be needed, but you might have to extend the enum
  }

  public int getNumberOfZeroes() {
    return zeroes;
  }

  public String getSuffix() {
    return suffix == null ? "" : "" + suffix;
  }

  public Threshold getHigherThreshold() {
    return higherThreshold;
  }
}

নাম্বারশোরনার.জভা :

import java.math.BigDecimal;
import java.math.RoundingMode;

public class NumberShortener {

  public static final int REQUIRED_PRECISION = 2;

  public static BigDecimal toPrecisionWithoutLoss(BigDecimal aBigDecimal,
      int aPrecision, RoundingMode aMode) {
    int previousScale = aBigDecimal.scale();
    int previousPrecision = aBigDecimal.precision();
    int newPrecision = Math.max(previousPrecision - previousScale, aPrecision);
    return aBigDecimal.setScale(previousScale + newPrecision - previousPrecision,
        aMode);
  }

  private static BigDecimal scaledNumber(BigDecimal aNumber, RoundingMode aMode) {
    Threshold threshold = Threshold.thresholdFor(aNumber);
    BigDecimal adjustedNumber = aNumber.movePointLeft(threshold.getNumberOfZeroes());
    BigDecimal scaledNumber = toPrecisionWithoutLoss(adjustedNumber, REQUIRED_PRECISION,
        aMode).stripTrailingZeros();
    // System.out.println("Number: <" + aNumber + ">, adjusted: <" + adjustedNumber
    // + ">, rounded: <" + scaledNumber + ">");
    return scaledNumber;
  }

  public static String shortenedNumber(long aNumber, RoundingMode aMode) {
    boolean isNegative = aNumber < 0;
    BigDecimal numberAsBigDecimal = new BigDecimal(isNegative ? -aNumber : aNumber);
    Threshold threshold = Threshold.thresholdFor(numberAsBigDecimal);
    BigDecimal scaledNumber = aNumber == 0 ? numberAsBigDecimal : scaledNumber(
        numberAsBigDecimal, aMode);
    if (scaledNumber.compareTo(new BigDecimal("1000")) >= 0) {
      scaledNumber = scaledNumber(scaledNumber, aMode);
      threshold = threshold.getHigherThreshold();
    }
    String sign = isNegative ? "-" : "";
    String printNumber = sign + scaledNumber.stripTrailingZeros().toPlainString()
        + threshold.getSuffix();
    // System.out.println("Number: <" + sign + numberAsBigDecimal + ">, rounded: <"
    // + sign + scaledNumber + ">, print: <" + printNumber + ">");
    return printNumber;
  }
}

( printlnবিবৃতিগুলি মন্তব্য করুন বা আপনার প্রিয় লগারটি এটি কী করছে তা ব্যবহার করার জন্য পরিবর্তন করুন))

এবং অবশেষে, নম্বর শোরটারনেস্টে পরীক্ষাগুলি (সরল JUnit 4):

import static org.junit.Assert.*;

import java.math.BigDecimal;
import java.math.RoundingMode;

import org.junit.Test;

public class NumberShortenerTest {

  private static final long[] NUMBERS_FROM_OP = new long[] { 1000, 5821, 10500, 101800, 2000000, 7800000, 92150000, 123200000 };
  private static final String[] EXPECTED_FROM_OP = new String[] { "1k", "5.8k", "10k", "101k", "2m", "7.8m", "92m", "123m" };
  private static final String[] EXPECTED_FROM_OP_HALF_UP = new String[] { "1k", "5.8k", "11k", "102k", "2m", "7.8m", "92m", "123m" };
  private static final long[] NUMBERS_TO_TEST = new long[] { 1, 500, 999, 1000, 1001, 1009, 1049, 1050, 1099, 1100, 12345, 123456, 999999, 1000000,
      1000099, 1000999, 1009999, 1099999, 1100000, 1234567, 999999999, 1000000000, 9123456789L, 123456789123L };
  private static final String[] EXPECTED_FROM_TEST = new String[] { "1", "500", "999", "1k", "1k", "1k", "1k", "1k", "1k", "1.1k", "12k", "123k",
      "999k", "1m", "1m", "1m", "1m", "1m", "1.1m", "1.2m", "999m", "1b", "9.1b", "123b" };
  private static final String[] EXPECTED_FROM_TEST_HALF_UP = new String[] { "1", "500", "999", "1k", "1k", "1k", "1k", "1.1k", "1.1k", "1.1k", "12k",
      "123k", "1m", "1m", "1m", "1m", "1m", "1.1m", "1.1m", "1.2m", "1b", "1b", "9.1b", "123b" };

  @Test
  public void testThresholdFor() {
    assertEquals(Threshold.ZERO, Threshold.thresholdFor(1));
    assertEquals(Threshold.ZERO, Threshold.thresholdFor(999));
    assertEquals(Threshold.THOUSAND, Threshold.thresholdFor(1000));
    assertEquals(Threshold.THOUSAND, Threshold.thresholdFor(1234));
    assertEquals(Threshold.THOUSAND, Threshold.thresholdFor(9999));
    assertEquals(Threshold.THOUSAND, Threshold.thresholdFor(999999));
    assertEquals(Threshold.MILLION, Threshold.thresholdFor(1000000));
  }

  @Test
  public void testToPrecision() {
    RoundingMode mode = RoundingMode.DOWN;
    assertEquals(new BigDecimal("1"), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("1.23456"), 1, mode));
    assertEquals(new BigDecimal("1.2"), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("1.23456"), 2, mode));
    assertEquals(new BigDecimal("1.23"), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("1.23456"), 3, mode));
    assertEquals(new BigDecimal("1.234"), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("1.23456"), 4, mode));
    assertEquals(new BigDecimal("999").toPlainString(), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("999"), 4, mode).stripTrailingZeros()
        .toPlainString());
    assertEquals(new BigDecimal("999").toPlainString(), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("999"), 2, mode).stripTrailingZeros()
        .toPlainString());
    assertEquals(new BigDecimal("999").toPlainString(), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("999.9"), 2, mode).stripTrailingZeros()
        .toPlainString());

    mode = RoundingMode.HALF_UP;
    assertEquals(new BigDecimal("1"), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("1.23456"), 1, mode));
    assertEquals(new BigDecimal("1.2"), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("1.23456"), 2, mode));
    assertEquals(new BigDecimal("1.23"), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("1.23456"), 3, mode));
    assertEquals(new BigDecimal("1.235"), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("1.23456"), 4, mode));
    assertEquals(new BigDecimal("999").toPlainString(), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("999"), 4, mode).stripTrailingZeros()
        .toPlainString());
    assertEquals(new BigDecimal("999").toPlainString(), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("999"), 2, mode).stripTrailingZeros()
        .toPlainString());
    assertEquals(new BigDecimal("1000").toPlainString(), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("999.9"), 2, mode)
        .stripTrailingZeros().toPlainString());
  }

  @Test
  public void testNumbersFromOP() {
    for (int i = 0; i < NUMBERS_FROM_OP.length; i++) {
      assertEquals("Index " + i + ": " + NUMBERS_FROM_OP[i], EXPECTED_FROM_OP[i],
          NumberShortener.shortenedNumber(NUMBERS_FROM_OP[i], RoundingMode.DOWN));
      assertEquals("Index " + i + ": " + NUMBERS_FROM_OP[i], EXPECTED_FROM_OP_HALF_UP[i],
          NumberShortener.shortenedNumber(NUMBERS_FROM_OP[i], RoundingMode.HALF_UP));
    }
  }

  @Test
  public void testBorders() {
    assertEquals("Zero: " + 0, "0", NumberShortener.shortenedNumber(0, RoundingMode.DOWN));
    assertEquals("Zero: " + 0, "0", NumberShortener.shortenedNumber(0, RoundingMode.HALF_UP));
    for (int i = 0; i < NUMBERS_TO_TEST.length; i++) {
      assertEquals("Index " + i + ": " + NUMBERS_TO_TEST[i], EXPECTED_FROM_TEST[i],
          NumberShortener.shortenedNumber(NUMBERS_TO_TEST[i], RoundingMode.DOWN));
      assertEquals("Index " + i + ": " + NUMBERS_TO_TEST[i], EXPECTED_FROM_TEST_HALF_UP[i],
          NumberShortener.shortenedNumber(NUMBERS_TO_TEST[i], RoundingMode.HALF_UP));
    }
  }

  @Test
  public void testNegativeBorders() {
    for (int i = 0; i < NUMBERS_TO_TEST.length; i++) {
      assertEquals("Index " + i + ": -" + NUMBERS_TO_TEST[i], "-" + EXPECTED_FROM_TEST[i],
          NumberShortener.shortenedNumber(-NUMBERS_TO_TEST[i], RoundingMode.DOWN));
      assertEquals("Index " + i + ": -" + NUMBERS_TO_TEST[i], "-" + EXPECTED_FROM_TEST_HALF_UP[i],
          NumberShortener.shortenedNumber(-NUMBERS_TO_TEST[i], RoundingMode.HALF_UP));
    }
  }
}

আমি যদি উল্লেখযোগ্য পরীক্ষার কেস মিস করি বা প্রত্যাশিত মানগুলি সামঞ্জস্য করা উচিত তবে মন্তব্যগুলিতে নির্দ্বিধায় নির্দ্বিধায়।


আপনার সমাধানের একমাত্র সুস্পষ্ট ক্ষতি আপনার কোডের জন্য ভি + এইচ-স্ক্রোলবারগুলি মনে হয়, এটি পঠনযোগ্যতা হ্রাস করে। আপনি কি মনে করেন যে স্পষ্টতা না হারিয়ে পুনর্নির্মাণ সম্ভব হবে?
ওল্ফ

@ ওল্ফ: আমার আইডিই থেকে অনুলিপি / পেস্ট নিয়ে দূরে সরে যাওয়ার আশা করছিল, তবে আপনি ঠিক বলেছেন, পাঠযোগ্যতার দাবি করা এবং অনুভূমিক স্ক্রোলিংয়ের প্রয়োজন আমার পক্ষে ভণ্ডামি, সুতরাং এটি নির্দেশ করার জন্য ধন্যবাদ thanks ;-) আমি কোডের প্রথম দুটি বিট আপডেট করেছি, যা হচ্ছে তা দেখার জন্য আপনি যা খুঁজছেন তা কিন্তু পরীক্ষার কোডটি রেখে গেছেন, কারণ এটি নিজের দ্বারা অনুসন্ধান করা এতটা সহায়ক নয় - আপনি ' ডি সম্ভবত ইউনিট পরীক্ষা চালাতে আপনার নিজের আইডিইতে এটি আটকে দিতে চান যদি আপনি দেখতে চান যে পরীক্ষাগুলি কাজ করে। আশা করি ঠিক আছে।
আমোস এম কার্পেন্টার

অই ভাল. তবে শেষ বাক্সে, পরীক্ষাগুলির ক্ষেত্রে, প্রত্যাশিত ফলাফলগুলি হতে পারে - অপটিক্যাল - ইনপুটগুলির সাথে আরও ভাল সম্পর্কিত (আমি প্রথম 6 অ্যারেতে আক্ষরিক অর্থ)।
ওল্ফ

@ ওল্ফ: আমি ফাঁকা জায়গা বা ট্যাবগুলির সাহায্যে একটি লাইনে আইটেমগুলিকে সারিবদ্ধ করার চেষ্টা করার অনুরাগী নই - এটি আমার প্রিয় ফর্ম্যাটারে (গ্রহন) সমস্ত ক্ষেত্রে সহজেই কনফিগার করা যায় না এবং ম্যানুয়ালি করা যায় না ... এইভাবে পাগলামি lies , প্রতিটি আইটেম যুক্ত বা সরিয়ে দেওয়ার সময় আপনাকে সমস্ত সমন্বয় করতে হবে। যদি আমি সত্যিই সেগুলি সারিবদ্ধ দেখতে চাইতাম তবে আমি কেবল একটি নম্বর স্প্রেডশিটে সিএসভি হিসাবে নম্বর / মানগুলি আটকে দেব।
আমোস এম কার্পেন্টার

1
সমস্ত আপনার উপর নির্ভর করে, @Asslias। আপনি যদি একমাত্র ব্যবহারের কেস সমাধান করার পরে থাকেন তবে আপনার সমাধানটি ঠিকভাবে কাজ করা উচিত; আমি TreeMapপদ্ধতির পছন্দ। "পাঠযোগ্যতা" অবশ্যই বিষয়বহুল। ;-) এখন যদি কেউ আপনার সংস্করণে কেটে ফেলার চেয়ে আলাদাভাবে গোল করতে চায়? (উদাহরণস্বরূপ, ফাইলের আকার নির্দেশ করতে এটি ব্যবহার করার সময়, কে কে কেটে ফেলতে চান?) আপনি যদি 10 এর পরিবর্তে 2 এর ক্ষমতা চান? আপনাকে মোটামুটি নতুন করে লিখতে হবে, তাই না? যেমনটি আমি বলেছিলাম, আমি ইচ্ছাকৃতভাবে আমার কোডটি গল্ফ করার চেষ্টা করছিলাম না, যার বেশিরভাগটি সংক্ষিপ্ত করা যেতে পারে (উদাহরণস্বরূপ, আমি কখনই এক লাইনে রাখি না)।
আমোস এম কার্পেন্টার

4

এটি আমার কোড পরিষ্কার এবং সহজ।

public static String getRoughNumber(long value) {
    if (value <= 999) {
        return String.valueOf(value);
    }

    final String[] units = new String[]{"", "K", "M", "B", "P"};
    int digitGroups = (int) (Math.log10(value) / Math.log10(1000));
    return new DecimalFormat("#,##0.#").format(value / Math.pow(1000, digitGroups)) + "" + units[digitGroups];

}

2

আমার নিজের উত্তর, জাভা কোড, স্ব বর্ণনামূলক কোড যুক্ত করা হচ্ছে ..

import java.math.BigDecimal;

/**
 * Method to convert number to formatted number.
 * 
 * @author Gautham PJ
 */
public class ShortFormatNumbers
{

    /**
     * Main method. Execution starts here.
     */
    public static void main(String[] args)
    {

        // The numbers that are being converted.
        int[] numbers = {999, 1400, 2500, 45673463, 983456, 234234567};


        // Call the "formatNumber" method on individual numbers to format 
        // the number.
        for(int number : numbers)
        {
            System.out.println(number + ": " + formatNumber(number));
        }

    }


    /**
     * Format the number to display it in short format.
     * 
     * The number is divided by 1000 to find which denomination to be added 
     * to the number. Dividing the number will give the smallest possible 
     * value with the denomination.
     * 
     * @param the number that needs to be converted to short hand notation.
     * @return the converted short hand notation for the number.
     */
    private static String formatNumber(double number)
    {
        String[] denominations = {"", "k", "m", "b", "t"};
        int denominationIndex = 0;

        // If number is greater than 1000, divide the number by 1000 and 
        // increment the index for the denomination.
        while(number > 1000.0)
        {
            denominationIndex++;
            number = number / 1000.0;
        }

        // To round it to 2 digits.
        BigDecimal bigDecimal = new BigDecimal(number);
        bigDecimal = bigDecimal.setScale(2, BigDecimal.ROUND_HALF_EVEN);


        // Add the number with the denomination to get the final value.
        String formattedNumber = bigDecimal + denominations[denominationIndex];
        return formattedNumber;
    }

}

1

এই কোড স্নিপেট কেবল মারাত্মক সহজ এবং পরিষ্কার কোড এবং সম্পূর্ণরূপে কাজ করে:

private static char[] c = new char[]{'K', 'M', 'B', 'T'};
private String formatK(double n, int iteration) {
    if (n < 1000) {
        // print 999 or 999K
        if (iteration <= 0) {
            return String.valueOf((long) n);
        } else {
            return String.format("%d%s", Math.round(n), c[iteration-1]);
        }
    } else if (n < 10000) {
        // Print 9.9K
        return String.format("%.1f%s", n/1000, c[iteration]);
    } else {
        // Increase 1 iteration
        return formatK(Math.round(n/1000), iteration+1);
    }
}

1

এটা চেষ্টা কর :

public String Format(Integer number){
    String[] suffix = new String[]{"k","m","b","t"};
    int size = (number.intValue() != 0) ? (int) Math.log10(number) : 0;
    if (size >= 3){
        while (size % 3 != 0) {
            size = size - 1;
        }
    }
    double notation = Math.pow(10, size);
    String result = (size >= 3) ? + (Math.round((number / notation) * 100) / 100.0d)+suffix[(size/3) - 1] : + number + "";
    return result
}

1
public class NumberToReadableWordFormat {

    public static void main(String[] args) {
        Integer[] numbers = new Integer[]{1000, 5821, 10500, 101800, 2000000, 7800000, 92150000, 123200000, 9999999,999};
        for(int n : numbers) {
            System.out.println(n + " => " + coolFormat(n));
        }
    }

    private static String[] c = new String[]{"K", "L", "Cr"};
    private static String coolFormat(int n) {
        int size = String.valueOf(n).length();
        if (size>=4 && size<6) {
                int value = (int) Math.pow(10, 1);
                double d = (double) Math.round(n/1000.0 * value) / value;
                return (double) Math.round(n/1000.0 * value) / value+" "+c[0];
        } else if(size>5 && size<8) {
                int value = (int) Math.pow(10, 1);
                return (double) Math.round(n/100000.0 * value) / value+" "+c[1];
        } else if(size>=8) {
                int value = (int) Math.pow(10, 1);
                return (double) Math.round(n/10000000.0 * value) / value+" "+c[2];
        } else {
            return n+"";
        }
    }
}

আউটপুট:

1000 => 1.0 K

5821 => 5.8 K

10500 => 10.5 K

101800 => 1.0 L

2000000 => 20.0 L

7800000 => 78.0 L

92150000 => 9.2 Cr

123200000 => 12.3 Cr

9999999 => 100.0 L

999 => 999

0
//code longer but work sure...

public static String formatK(int number) {
    if (number < 999) {
        return String.valueOf(number);
    }

    if (number < 9999) {
        String strNumber = String.valueOf(number);
        String str1 = strNumber.substring(0, 1);
        String str2 = strNumber.substring(1, 2);
        if (str2.equals("0")) {
            return str1 + "k";
        } else {
            return str1 + "." + str2 + "k";
        }
    }

    if (number < 99999) {
        String strNumber = String.valueOf(number);
        String str1 = strNumber.substring(0, 2);
        return str1 + "k";
    }

    if (number < 999999) {
        String strNumber = String.valueOf(number);
        String str1 = strNumber.substring(0, 3);
        return str1 + "k";
    }

    if (number < 9999999) {
        String strNumber = String.valueOf(number);
        String str1 = strNumber.substring(0, 1);
        String str2 = strNumber.substring(1, 2);
        if (str2.equals("0")) {
            return str1 + "m";
        } else {
            return str1 + "." + str2 + "m";
        }
    }

    if (number < 99999999) {
        String strNumber = String.valueOf(number);
        String str1 = strNumber.substring(0, 2);
        return str1 + "m";
    }

    if (number < 999999999) {
        String strNumber = String.valueOf(number);
        String str1 = strNumber.substring(0, 3);
        return str1 + "m";
    }

    NumberFormat formatterHasDigi = new DecimalFormat("###,###,###");
    return formatterHasDigi.format(number);
}

2
এটি আপনার সমস্ত প্রান্তের ক্ষেত্রে কাজ করে না। উদাহরণস্বরূপ 999 ব্যবহার করে দেখুন।
জেডডি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.