這個是我花49c幣在csdn上下載的,稍微做了些修改,給大家分享一下。覺得還不錯的點個贊吧。
package com.dq.utils;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
/**
* 獲取砍價的集合公共方法
* 2018年6月4日 上午9:35:57
* version 1.0
*
* @author lwf
*/
public class BargainCommonUtils {
private static final Logger logger = LoggerFactory.getLogger(BargainCommonUtils.class);
/**
* 砍價算法優化,避免死循環和空指針
* <br/>爲避免價格生成出錯,要求:count<=100;price/count>=0.08
* <br/>2018年8月14日 上午9:54:39
* <br/>version 1.0
* <br/>@author lwf
* <br/>@param count
* <br/>@param price
* <br/>@param finalPrice
* <br/>@return
*/
public static List<BigDecimal> getBargainList(Integer count, BigDecimal price, BigDecimal finalPrice) {
List<BigDecimal> list = new BargainCommonUtils().getTempBargainList(count, price, finalPrice);
int i = 0;
while (list == null || list.size() == 0 || list.size() != count) {
list = new BargainCommonUtils().getTempBargainList(count, price, finalPrice);
i++;
if (i > 50000) {
logger.info("砍價集合生成超時!請重試或重新設定價格/次數比例!");
break;
}
}
return list;
}
/*
* 獲取砍價的價格集合
* <br/>2018年6月7日 下午4:32:31
* <br/>version 1.0
* <br/>@author lwf
*/
public static List<BigDecimal> getTempBargainList(Integer count, BigDecimal price, BigDecimal finalPrice) {
BigDecimal sourcePrice = price;
sourcePrice = sourcePrice.subtract(finalPrice); // 實際要折扣掉的金額
sourcePrice = sourcePrice.setScale(2, RoundingMode.HALF_DOWN);// 把多餘的小數點去掉
ArrayList<BigDecimal> tempPrices = new ArrayList<>();// 實際被砍掉的價格集合
Map<String, BigDecimal> lastPrice = new HashMap<>();// 最後一次的砍價剩餘的價格
int sum = 0;// 實際砍價次數
ArrayList<BigDecimal> finalPrices = new ArrayList<>(); // 最終所需要的砍價集合
finalPrice = new BigDecimal(0);
BigDecimal divisor = new BigDecimal(count);
// 獲取砍價的平均值
int countTmep = 2;
getPirces(sourcePrice, countTmep, tempPrices, finalPrice, lastPrice);
tempPrices.add(lastPrice.get("lastPrice"));
sum = tempPrices.size();
if (sum > count) { // 如果實際砍價次數大於預期次數,則再進行處理
int temp = sum - count;// 相差次數
BigDecimal sumPrice = new BigDecimal(0.00);
for (int i = 0; i < tempPrices.size(); i++) {
if (i < tempPrices.size() - temp) {
finalPrices.add(tempPrices.get(i));
} else {
sumPrice = sumPrice.add(tempPrices.get(i)); // 多餘的砍價
}
}
// 把多餘的砍價平均分散到前count中的砍價
BigDecimal divide = null;
try {
divide = sumPrice.divide(new BigDecimal(count), 2, RoundingMode.HALF_DOWN);
} catch (Exception e) {
logger.warn(e.getMessage());
e.printStackTrace();
}
divide = divide.setScale(2, RoundingMode.HALF_DOWN);
for (int i = 0; i < finalPrices.size(); i++) {
BigDecimal add = finalPrices.get(i).add(divide);
finalPrices.set(i, add);
}
} else if (sum == count) {
finalPrices = tempPrices;
} else {
return null;
}
// 價格矯正 補總差價,多減少增
BigDecimal totalPrice = new BigDecimal(0);
for (BigDecimal bd : finalPrices) {
totalPrice = bd.add(totalPrice);
}
logger.info("價格矯正前的totalPrice:" + totalPrice);
// 如果集合中的總價大於實際原價,則把集合中任意一個大於這個差價的價格減去差價(誤差都不會超過0.1)
int inFlag = 0;
if (totalPrice.compareTo(sourcePrice) > 0) {
BigDecimal subtract = totalPrice.subtract(sourcePrice);
for (int i = 0; i < finalPrices.size(); i++) {
if (finalPrices.get(i).compareTo(subtract) > 0) { // 集合中的大於這個差價的價格
BigDecimal changedPrice = finalPrices.get(i).subtract(subtract);
finalPrices.set(i, changedPrice);
inFlag = 1;
break;
}
}
}
if (totalPrice.compareTo(sourcePrice) < 0) { // 如果集合中的總價小於等於實際原價,則把集合中最後一個價格加上差價(誤差都不會超過0.1)
BigDecimal subtract = sourcePrice.subtract(totalPrice);
BigDecimal sourceLastPrice = finalPrices.get(finalPrices.size() - 1);
BigDecimal changedPrice = sourceLastPrice.add(subtract);
finalPrices.set(finalPrices.size() - 1, changedPrice);
inFlag = 1;
}
if (totalPrice.compareTo(sourcePrice) == 0) {
inFlag = 1;
}
if (inFlag == 0) { // 如果沒有價格大於這個差價,則再完整的調一次本方法
return null;
} else {
logger.info("sourcePrice:" + sourcePrice);
logger.info("*********************************");
totalPrice = new BigDecimal(0);
for (BigDecimal bd : finalPrices) {
totalPrice = bd.add(totalPrice);
}
logger.info("預期砍價次數:" + count + " 實際砍價次數:" + finalPrices.size() + " 價格矯正後的totalPrice:" + totalPrice);
logger.info(Arrays.toString(finalPrices.toArray()));
return finalPrices;
}
}
/**
* 獲取被砍的價格集合
* <br/>2018年6月4日 下午3:19:07
* <br/>version 1.0
* <br/>@author lwf
* <br/>@param sourcePrice 原價
* <br/>@param avgPrice 砍價平均值: 原價/砍價次數=砍價平均值
* <br/>@param tempPrices 砍價價格集合
* <br/>@param finalPrice 最終價
*/
public static void getPirces(BigDecimal sourcePrice, int countTemp, List<BigDecimal> tempPrices, BigDecimal finalPrice, Map<String, BigDecimal> lastPrice) {
Random r = new Random();
double d = sourcePrice.divide(new BigDecimal(++countTemp), 2, RoundingMode.HALF_DOWN).doubleValue();
if (tempPrices.size() > 0 && tempPrices.size() % 4 == 0) {
countTemp = countTemp - 3;
}
Double randomPrice = r.nextDouble() * d + 0.01; // 例如:生成0到9.99之間的隨機數
BigDecimal bargainPrice = new BigDecimal(randomPrice); // 被砍掉的價格
bargainPrice = bargainPrice.setScale(2, RoundingMode.HALF_DOWN);
BigDecimal surplusPrice = sourcePrice.subtract(bargainPrice); // 剩餘價格
if (surplusPrice.compareTo(finalPrice) <= 0) {
return;
}
tempPrices.add(bargainPrice);
lastPrice.put("lastPrice", surplusPrice);
getPirces(surplusPrice, countTemp, tempPrices, finalPrice, lastPrice);
}
/* @Test
public void testBargain() {
int count = 100;
BigDecimal price = new BigDecimal(7);
BigDecimal finalPrice = new BigDecimal(0);
List<BigDecimal> list = new BargainCommonServiceImpl().getTempBargainList(count, price, finalPrice);
int i = 0;
while(list==null || list.size()==0||list.size()!=count) {
list = new BargainCommonServiceImpl().getTempBargainList(count, price, finalPrice);
i ++;
if(i>50000) {
logger.info("砍價集合生成超時!請重試或重新設定價格/次數比例!");
System.out.println("砍價集合生成超時!請重試或重新設定價格/次數比例!");
break;
}
}
System.out.println(i);
}*/
public static void main(String[] args) {
int count = 10;
BigDecimal price = BigDecimal.valueOf(7L);
BigDecimal finalPrice =BigDecimal.ZERO;
List<BigDecimal> list = BargainCommonUtils.getTempBargainList(count, price, finalPrice);
list.forEach(bigDecimal -> {
System.out.printf(bigDecimal.toString());
});
}
}