Другая версия C # с ленивым поколением комбинационных индексов. Эта версия поддерживает единый массив индексов для определения сопоставления между списком всех значений и значениями для текущей комбинации, т. Е. Постоянно использует дополнительное пространство O (k) в течение всего времени выполнения. Код генерирует отдельные комбинации, включая первый, в O (k) времени.
public static IEnumerable<T[]> Combinations<T>(this T[] values, int k)
{
if (k < 0 || values.Length < k)
yield break; // invalid parameters, no combinations possible
// generate the initial combination indices
var combIndices = new int[k];
for (var i = 0; i < k; i++)
{
combIndices[i] = i;
}
while (true)
{
// return next combination
var combination = new T[k];
for (var i = 0; i < k; i++)
{
combination[i] = values[combIndices[i]];
}
yield return combination;
// find first index to update
var indexToUpdate = k - 1;
while (indexToUpdate >= 0 && combIndices[indexToUpdate] >= values.Length - k + indexToUpdate)
{
indexToUpdate--;
}
if (indexToUpdate < 0)
yield break; // done
// update combination indices
for (var combIndex = combIndices[indexToUpdate] + 1; indexToUpdate < k; indexToUpdate++, combIndex++)
{
combIndices[indexToUpdate] = combIndex;
}
}
}
Код теста:
foreach (var combination in new[] {'a', 'b', 'c', 'd', 'e'}.Combinations(3))
{
System.Console.WriteLine(String.Join(" ", combination));
}
Выход:
a b c
a b d
a b e
a c d
a c e
a d e
b c d
b c e
b d e
c d e
Я не думаю, что это возможно. Какой у вас вариант использования? Я считаю, что C # ArrayLists имеет свойство .capacity, но класс Java ArrayList не предоставляет эту информацию.
У вас есть конструктор, который принимает начальный аргумент емкости, и у вас есть метод sureCapacity (), который вы могли бы использовать для уменьшения количества постепенного перераспределения.
У вас также есть метод trimToSize (), который вы можете использовать, если действительно беспокоитесь об использовании памяти.
Не помню, было ли это, но вы могли бы сделать это самостоятельно, посмотрев на исходный код ArrayList. Разработчики Java должны использовать преимущества исходного кода, поставляемого в комплекте с SDK.
Емкость по умолчанию ArrayList
равна 10. Как только максимальный размер будет достигнут, новая емкость будет:
новая емкость = (текущая емкость * 3/2) +1.
Я только что проверил документацию sun по классу ArrayList , и единственный метод, который я видел, связанный с емкостью, был sureCapacity ( int minCapacity), что не совсем то, что вам нужно. Удачи!
Вы можете получить это отражение:
public abstract class ArrayListHelper {
static final Field field;
static {
try {
field = ArrayList.class.getDeclaredField("elementData");
field.setAccessible(true);
} catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}
@SuppressWarnings("unchecked")
public static <E> int getArrayListCapacity(ArrayList<E> arrayList) {
try {
final E[] elementData = (E[]) field.get(arrayList);
return elementData.length;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
Посмотрев на спецификацию ArrayList, я не вижу метода, который предоставляет эту информацию.
Тем не менее, метод ensureCapacity кажется шагом в правильном направлении (предупреждение: он не гарантирует правильного ответа): При вызове он гарантирует, что емкость не меньше указанного аргумента. Таким образом, если реализация ArrayList
использует этот метод для обеспечения емкости (в отличие от вызова какого-либо частного метода/манипулирования соответствующими полями напрямую), вы можете получить текущую емкость, переопределив этот метод. Вам также необходимо переопределить trimToSize()
аналогичным образом.
Конечно, это решение не очень переносимо, поскольку другая реализация ArrayList
(на JVM другого производителя) может делать все по-другому.
Вот как должен выглядеть код
public class CapacityTrackingArrayList<T> extends ArrayList<T> {
// declare a constructor for each ArrayList constructor ...
// Now, capacity tracking stuff:
private int currentCapacity = 10;
public int getCapacity() { return currentCapacity; }
public void ensureCapacity(int arg) {
currentCapacity = arg;
super.ensureCapacity(arg);
}
public void trimToSize() { currentCapacity = size(); super.trimToSize(); }
}