Как автоматически решить число десятичных знаков в python? [Дубликат]

Большинство ответов здесь дают полезные советы, когда у вас есть одна операция async, но иногда это возникает, когда вам нужно выполнить асинхронную операцию для каждой записи в массиве или другом списке подобная структура. Искушение состоит в том, чтобы сделать это:

// WRONG
var results = [];
theArray.forEach(function(entry) {
    doSomethingAsync(entry, function(result) {
        results.push(result);
    });
});
console.log(results); // E.g., using them, returning them, etc.

Пример:

// WRONG
var theArray = [1, 2, 3];
var results = [];
theArray.forEach(function(entry) {
    doSomethingAsync(entry, function(result) {
        results.push(result);
    });
});
console.log("Results:", results); // E.g., using them, returning them, etc.

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
  max-height: 100% !important;
}

Причина, 't работа заключается в том, что обратные вызовы из doSomethingAsync еще не запущены к тому моменту, когда вы пытаетесь использовать результаты.

Итак, если у вас есть массив (или список какого-то типа) и хотите выполнять асинхронные операции для каждой записи, у вас есть два варианта: выполнять операции параллельно (перекрывающиеся) или последовательно (последовательно последовательно).

Параллельный

Вы могут запускать все из них и отслеживать количество обратных вызовов, которые вы ожидаете, а затем использовать результаты, когда вы получили много обратных вызовов:

var results = [];
var expecting = theArray.length;
theArray.forEach(function(entry, index) {
    doSomethingAsync(entry, function(result) {
        results[index] = result;
        if (--expecting === 0) {
            // Done!
            console.log("Results:", results); // E.g., using the results
        }
    });
});

Пример:

var theArray = [1, 2, 3];
var results = [];
var expecting = theArray.length;
theArray.forEach(function(entry, index) {
    doSomethingAsync(entry, function(result) {
        results[index] = result;
        if (--expecting === 0) {
            // Done!
            console.log("Results:", results); // E.g., using the results
        }
    });
});

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
  max-height: 100% !important;
}

(Мы могли бы покончить с expecting и просто использовать results.length === theArray.length, но это оставляет нам открытым возможность того, что theArray изменяется, пока вызовы выдающиеся ...)

Обратите внимание, как мы используем index из forEach, чтобы сохранить результат в results в том же положении, что и запись это относится, даже если результаты a (поскольку асинхронные вызовы не обязательно завершаются в том порядке, в котором они были запущены).

Но что, если вам нужно вернуть те результаты от функции? Как указывали другие ответы, вы не можете; вы должны принять вашу функцию и вызвать обратный вызов (или вернуть Promise ). Вот вариант обратного вызова:

function doSomethingWith(theArray, callback) {
    var results = [];
    var expecting = theArray.length;
    theArray.forEach(function(entry, index) {
        doSomethingAsync(entry, function(result) {
            results[index] = result;
            if (--expecting === 0) {
                // Done!
                callback(results);
            }
        });
    });
}
doSomethingWith(theArray, function(results) {
    console.log("Results:", results);
});

Пример:

function doSomethingWith(theArray, callback) {
    var results = [];
    var expecting = theArray.length;
    theArray.forEach(function(entry, index) {
        doSomethingAsync(entry, function(result) {
            results[index] = result;
            if (--expecting === 0) {
                // Done!
                callback(results);
            }
        });
    });
}
doSomethingWith([1, 2, 3], function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
  max-height: 100% !important;
}

Или вот версия, возвращающая Promise вместо:

function doSomethingWith(theArray) {
    return new Promise(function(resolve) {
        var results = [];
        var expecting = theArray.length;
        theArray.forEach(function(entry, index) {
            doSomethingAsync(entry, function(result) {
                results[index] = result;
                if (--expecting === 0) {
                    // Done!
                    resolve(results);
                }
            });
        });
    });
}
doSomethingWith(theArray).then(function(results) {
    console.log("Results:", results);
});

Конечно, если doSomethingAsync передал нам ошибки, мы использовали бы reject, чтобы отклонить обещание, когда мы получили сообщение об ошибке.)

Пример:

function doSomethingWith(theArray) {
    return new Promise(function(resolve) {
        var results = [];
        var expecting = theArray.length;
        theArray.forEach(function(entry, index) {
            doSomethingAsync(entry, function(result) {
                results[index] = result;
                if (--expecting === 0) {
                    // Done!
                    resolve(results);
                }
            });
        });
    });
}
doSomethingWith([1, 2, 3]).then(function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
  max-height: 100% !important;
}

(Или, альтернативно, вы можете сделать обертку для doSomethingAsync, который возвращает обещание, а затем сделайте следующее ...)

Если doSomethingAsync дает вам Promise , вы можете использовать Promise.all :

function doSomethingWith(theArray) {
    return Promise.all(theArray.map(function(entry) {
        return doSomethingAsync(entry, function(result) {
            results.push(result);
        });
    }));
}
doSomethingWith(theArray).then(function(results) {
    console.log("Results:", results);
});

Пример:

function doSomethingWith(theArray) {
    return Promise.all(theArray.map(function(entry) {
        return doSomethingAsync(entry, function(result) {
            results.push(result);
        });
    }));
}
doSomethingWith([1, 2, 3]).then(function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value) {
    console.log("Starting async operation for " + value);
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log("Completing async operation for " + value);
            resolve(value * 2);
        }, Math.floor(Math.random() * 200));
    });
}
.as-console-wrapper {
  max-height: 100% !important;
}

Обратите внимание, что Promise.all решает свое обещание с помощью массива результатов всех обещаний, которые вы даете ему, когда все они разрешены, или отвергает его обещание, когда первый обещаний, которые вы ему даете, отклоняет.

Серия

Предположим, вы не хотите, чтобы операции были параллельны? Если вы хотите запускать их один за другим, вам нужно дождаться завершения каждой операции до начала следующего. Вот пример функции, которая делает это, и вызывает обратный вызов с результатом:

function doSomethingWith(theArray, callback) {
    var results = [];
    doOne(0);
    function doOne(index) {
        if (index < theArray.length) {
            doSomethingAsync(theArray[index], function(result) {
                results.push(result);
                doOne(index + 1);
            });
        } else {
            // Done!
            callback(results);
        }
    }
}
doSomethingWith(theArray, function(results) {
    console.log("Results:", results);
});

(Поскольку мы выполняем работу последовательно, мы можем просто использовать results.push(result), так как мы знаю, что мы не получим результаты не в порядке. В приведенном выше примере мы могли бы использовать results[index] = result;, но в некоторых из следующих примеров у нас нет индекса для использования.)

Пример:

function doSomethingWith(theArray, callback) {
    var results = [];
    doOne(0);
    function doOne(index) {
        if (index < theArray.length) {
            doSomethingAsync(theArray[index], function(result) {
                results.push(result);
                doOne(index + 1);
            });
        } else {
            // Done!
            callback(results);
        }
    }
}
doSomethingWith([1, 2, 3], function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
  max-height: 100% !important;
}

(Или снова создайте обертку для doSomethingAsync, которая дает вам обещание и выполните ниже ...)

Если doSomethingAsync дает вам обещание, если вы можете использовать синтаксис ES2017 + (возможно, с транспилером, например Babel ), вы можете использовать функцию async с помощью for-of и await :

async function doSomethingWith(theArray) {
    const results = [];
    for (const entry of theArray) {
        results.push(await doSomethingAsync(entry));
    }
    return results;
}
doSomethingWith(theArray).then(results => {
    console.log("Results:", results);
});

Пример:

async function doSomethingWith(theArray) {
    const results = [];
    for (const entry of theArray) {
        results.push(await doSomethingAsync(entry));
    }
    return results;
}
doSomethingWith([1, 2, 3]).then(function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value) {
    console.log("Starting async operation for " + value);
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log("Completing async operation for " + value);
            resolve(value * 2);
        }, Math.floor(Math.random() * 200));
    });
}
.as-console-wrapper {
  max-height: 100% !important;
}

Если вы не можете использовать синтаксис ES2017 + (пока), вы можете использовать вариацию на Обещают уменьшить шаблон (это сложнее, чем обычное сокращение Promise, потому что мы не передаем результат от одного к другому, а вместо gat

function doSomethingWith(theArray) {
    return theArray.reduce(function(p, entry) {
        return p.then(function(results) {
            return doSomethingAsync(entry).then(function(result) {
                results.push(result);
                return results;
            });
        });
    }, Promise.resolve([]));
}
doSomethingWith(theArray).then(function(results) {
    console.log("Results:", results);
});

Пример:

function doSomethingWith(theArray) {
    return theArray.reduce(function(p, entry) {
        return p.then(function(results) {
            return doSomethingAsync(entry).then(function(result) {
                results.push(result);
                return results;
            });
        });
    }, Promise.resolve([]));
}
doSomethingWith([1, 2, 3]).then(function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value) {
    console.log("Starting async operation for " + value);
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log("Completing async operation for " + value);
            resolve(value * 2);
        }, Math.floor(Math.random() * 200));
    });
}
.as-console-wrapper {
  max-height: 100% !important;
}

.. , который менее громоздк с функциями стрелок ES2015 + :

function doSomethingWith(theArray) {
    return theArray.reduce((p, entry) => p.then(results => doSomethingAsync(entry).then(result => {
        results.push(result);
        return results;
    })), Promise.resolve([]));
}
doSomethingWith(theArray).then(results => {
    console.log("Results:", results);
});

Пример:

function doSomethingWith(theArray) {
    return theArray.reduce((p, entry) => p.then(results => doSomethingAsync(entry).then(result => {
        results.push(result);
        return results;
    })), Promise.resolve([]));
}
doSomethingWith([1, 2, 3]).then(function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value) {
    console.log("Starting async operation for " + value);
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log("Completing async operation for " + value);
            resolve(value * 2);
        }, Math.floor(Math.random() * 200));
    });
}
.as-console-wrapper {
  max-height: 100% !important;
}

118
задан Jon Clements 27 March 2014 в 19:24
поделиться

14 ответов

Me, я бы сделал ('%f' % x).rstrip('0').rstrip('.') - гарантирует форматирование с фиксированной запятой, а не научную нотацию и т. д. и т. д. Да, не такой гладкий и элегантный, как %g, но он работает (и я не знаю как заставить %g никогда не использовать научную нотацию, -).

137
ответ дан Alex Martelli 3 September 2018 в 17:53
поделиться

Используйте% g с большой шириной, например «% .99g».

EDIT: он не работает

>>> '%.99g' % 0.0000001
'9.99999999999999954748111825886258685613938723690807819366455078125e-08'
0
ответ дан alexanderlukanin13 3 September 2018 в 17:53
поделиться

Как пробовать самый простой и, вероятно, самый эффективный подход? Метод normalize () удаляет все самые правые конечные нули.

from decimal import Decimal

print (Decimal('0.001000').normalize())
# Result: 0.001

Работает в Python 2 и Python 3.

- Обновлено -

проблема только в том, что @ BobStein-VisiBone отметил, что цифры, такие как 10, 100, 1000 ... будут отображаться в экспоненциальном представлении. Это можно легко исправить, используя следующую функцию:

from decimal import Decimal


def format_float(f):
    d = Decimal(str(f));
    return d.quantize(Decimal(1)) if d == d.to_integral() else d.normalize()
9
ответ дан Ander 3 September 2018 в 17:53
поделиться

Вы можете просто использовать format () для достижения этого:

format(3.140, '.10g') где 10 - это точная точность.

2
ответ дан clel 3 September 2018 в 17:53
поделиться

Для float вы можете использовать это:

def format_float(num):
    return ('%i' if num == int(num) else '%s') % num

Проверить его:

>>> format_float(1.00000)
'1'
>>> format_float(1.1234567890000000000)
'1.123456789'

Для десятичного числа см. решение здесь: https://stackoverflow.com/ а / 42668598/5917543

0
ответ дан Community 3 September 2018 в 17:53
поделиться

Если вы можете жить с 3. и 3.0, появляясь как «3.0», очень простой подход, который выравнивает нули из представлений float:

print("%s"%3.140)

(спасибо @ellimilial за указание исключений )

1
ответ дан drevicko 3 September 2018 в 17:53
поделиться

Вот решение, которое сработало для меня. Это сочетание из решения с помощью PolyMesh и использование нового синтаксиса .format() .

for num in 3, 3., 3.0, 3.1, 3.14, 3.140:
    print('{0:.2f}'.format(num).rstrip('0').rstrip('.'))

Выход:

3
3
3
3.1
3.14
3.14
3
ответ дан Kaushal Modi 3 September 2018 в 17:53
поделиться

OP хотел бы удалить сверкающие нули и сделать результирующую строку как можно короче.

Я нахожу, что экспоненциальное форматирование% g сокращает результирующую строку для очень больших и очень малых значений. Проблема возникает для значений, для которых не требуется экспоненциальная запись, например 128.0, которая не является ни очень большой, ни очень малой.

Вот один из способов форматирования чисел как коротких строк, которые используют экспоненциальную нотацию% g только тогда, когда Decimal.normalize создает слишком длинные строки. Это может быть не самое быстрое решение (поскольку оно использует Decimal.normalize)

def floatToString (inputValue, precision = 3):
    rc = str(Decimal(inputValue).normalize())
    if 'E' in rc or len(rc) > 5:
        rc = '{0:.{1}g}'.format(inputValue, precision)        
    return rc

inputs = [128.0, 32768.0, 65536, 65536 * 2, 31.5, 1.000, 10.0]

outputs = [floatToString(i) for i in inputs]

print(outputs)

# ['128', '32768', '65536', '1.31e+05', '31.5', '1', '10']
0
ответ дан kinok 3 September 2018 в 17:53
поделиться

Вы можете достичь этого в большинстве pythonic образом:

python3:

"{:0.0f}".format(num)
-3
ответ дан Lan Vukušič 3 September 2018 в 17:53
поделиться

После просмотра ответов на несколько похожих вопросов это кажется лучшим решением для меня:

def floatToString(inputValue):
    return ('%.15f' % inputValue).rstrip('0').rstrip('.')

Мое рассуждение:

%g не избавляется

>>> '%g' % 0.000035
'3.5e-05'

15 десятичных знаков, похоже, избегают странного поведения и имеют большую точность для моих потребностей.

>>> ('%.15f' % 1.35).rstrip('0').rstrip('.')
'1.35'
>>> ('%.16f' % 1.35).rstrip('0').rstrip('.')
'1.3500000000000001'

Я мог бы использовать format(inputValue, '.15f'). вместо '%.15f' % inputValue, но это немного медленнее (~ 30%).

Я мог бы использовать Decimal(inputValue).normalize(), но в этом есть несколько проблем. Во-первых, он медленнее (~ 11x). Я также обнаружил, что, хотя он имеет довольно высокую точность, он все еще страдает от потери точности при использовании normalize().

>>> Decimal('0.21000000000000000000000000006').normalize()
Decimal('0.2100000000000000000000000001')
>>> Decimal('0.21000000000000000000000000006')
Decimal('0.21000000000000000000000000006')

Самое главное, что я все еще буду преобразовывать в Decimal из float что может привести к тому, что вы получите что-то иное, чем число, которое вы там вложили. Я думаю, что Decimal работает лучше всего, когда арифметика остается в Decimal, а Decimal инициализируется строкой.

>>> Decimal(1.35)
Decimal('1.350000000000000088817841970012523233890533447265625')
>>> Decimal('1.35')
Decimal('1.35')

Я уверен, что точность Decimal.normalize() может быть отрегулирована к тому, что необходимо с использованием настроек контекста, но учитывая уже медленную скорость и не требующую смешной точности, и тот факт, что я все равно буду переходить с поплавка и потерять точность, я не думал, что это стоит того.

Меня не интересует возможный результат «-0», поскольку -0.0 является допустимым числом с плавающей запятой, и, вероятно, это будет редкое событие, но, поскольку вы упомянули о том, что хотите сохранить результат строки как короткий насколько это возможно, вы всегда можете использовать дополнительные условные условия при очень низкой стоимости скорости.

def floatToString(inputValue):
    result = ('%.15f' % inputValue).rstrip('0').rstrip('.')
    return '0' if result == '-0' else result
8
ответ дан PolyMesh 3 September 2018 в 17:53
поделиться

Несмотря на то, что форматирование, скорее всего, имеет большую часть Pythonic, это альтернативное решение, использующее инструмент more_itertools.rstrip .

import more_itertools as mit


def fmt(num, pred=None):
    iterable = str(num)
    predicate = pred if pred is not None else lambda x: x in {".", "0"}
    return "".join(mit.rstrip(iterable, predicate))

assert fmt(3) == "3"
assert fmt(3.) == "3"
assert fmt(3.0) == "3"
assert fmt(3.1) == "3.1"
assert fmt(3.14) == "3.14"
assert fmt(3.140) == "3.14"
assert fmt(3.14000) == "3.14"
assert fmt("3,0", pred=lambda x: x in set(",0")) == "3"

Число преобразуется в строку, которая лишен завершающих символов, которые удовлетворяют предикату. Определение функции fmt не требуется, но оно используется здесь для проверки утверждений, которые все проходят. Примечание: он работает с строковыми вводами и принимает необязательные предикаты.

См. Также подробную информацию об этой сторонней библиотеке, more_itertools .

1
ответ дан pylang 3 September 2018 в 17:53
поделиться
>>> str(a if a % 1 else int(a))
1
ответ дан Shameem 3 September 2018 в 17:53
поделиться

Вы можете использовать max() следующим образом:

print(max(int(x), x))

0
ответ дан Simon 3 September 2018 в 17:53
поделиться

Вы можете использовать %g для достижения этого:

'%g'%(3.140)

или для Python 2.6 или лучше:

'{0:g}'.format(3.140)

Из документов для format : g вызывает (между прочим)

несущественные конечные нули, которые будут удалены из значения, а десятичная точка также удаляется, если нет оставшихся цифр следуя за ним.

113
ответ дан unutbu 3 September 2018 в 17:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: