我有这样的代码:
public static String SelectRandomFromTemplate(String template,int count) {
String[] split = template.split("|");
List<String> list=Arrays.asList(split);
Random r = new Random();
while( list.size() > count ) {
list.remove(r.nextInt(list.size()));
}
return StringUtils.join(list, ", ");
}
我明白了:
06-03 15:05:29.614: ERROR/AndroidRuntime(7737): java.lang.UnsupportedOperationException
06-03 15:05:29.614: ERROR/AndroidRuntime(7737): at java.util.AbstractList.remove(AbstractList.java:645)
这样做是正确的吗?Java.15
Arrays.asList()返回一个不允许操作影响其大小的列表(注意,这与“不可修改”不同)。
你可以写new ArrayList<String>(Arrays.asList(split));来创建一个真正的副本,但看到你正在尝试做什么,这里有一个额外的建议(你有一个O(n²)算法在下面)。
你想从列表中删除list.size() - count(我们称之为k)随机元素。只是选择尽可能多的随机元素,并将它们交换到列表的最后k个位置,然后删除整个范围(例如使用subList()和clear())。这将把它变成一个精简和平均O(n)算法(O(k)更精确)。
更新:如下所述,这个算法只在元素是无序的情况下才有意义,例如,如果List表示一个Bag。另一方面,如果List具有有意义的顺序,则该算法不会保留它(polygeneluants的算法会保留它)。
更新2:所以回想起来,一个更好的(线性,保持顺序,但有O(n)个随机数)算法应该是这样的:
LinkedList<String> elements = ...; //to avoid the slow ArrayList.remove()
int k = elements.size() - count; //elements to select/delete
int remaining = elements.size(); //elements remaining to be iterated
for (Iterator i = elements.iterator(); k > 0 && i.hasNext(); remaining--) {
i.next();
if (random.nextInt(remaining) < k) {
//or (random.nextDouble() < (double)k/remaining)
i.remove();
k--;
}
}
取代
List<String> list=Arrays.asList(split);
to
List<String> list = New ArrayList<>();
list.addAll(Arrays.asList(split));
or
List<String> list = new ArrayList<>(Arrays.asList(split));
or
List<String> list = new ArrayList<String>(Arrays.asList(split));
或(更适合删除元素)
List<String> list = new LinkedList<>(Arrays.asList(split));
你的代码有很多问题:
在数组。返回一个固定大小的列表
来自API:
数组。asList:返回指定数组支持的固定大小的列表。
你不能再加了;你不能从中移走。您不能在结构上修改List。
Fix
创建一个LinkedList,支持更快的删除。
List<String> list = new LinkedList<String>(Arrays.asList(split));
在分割取正则表达式时
来自API:
字符串。split(String regex):根据给定正则表达式的匹配情况拆分字符串。
|是一个正则元字符;如果你想拆分一个字面值|,你必须将它转义到\|,它作为一个Java字符串字面值是“\\|”。
Fix:
template.split("\\|")
更好的算法
与其每次使用随机索引调用remove一个,不如在范围内生成足够多的随机数,然后使用listIterator()遍历List一次,在适当的索引处调用remove()。关于如何在给定范围内生成随机但不同的数字,有关于stackoverflow的问题。
这样,你的算法就是O(N)