Очень эффективный алгоритм, адаптированный из книги Йорга Арндта «Вычислительные вопросы»
(Глава 7.2 Co-lexicographic order for compositions into exactly k parts
)
n = 4
k = 3
x = [0] * n
x[0] = k
while True:
print(x)
v = x[-1]
if (k==v ):
break
x[-1] = 0
j = -2
while (0==x[j]):
j -= 1
x[j] -= 1
x[j+1] = 1 + v
[3, 0, 0, 0]
[2, 1, 0, 0]
[2, 0, 1, 0]
[2, 0, 0, 1]
[1, 2, 0, 0]
[1, 1, 1, 0]
[1, 1, 0, 1]
[1, 0, 2, 0]
[1, 0, 1, 1]
[1, 0, 0, 2]
[0, 3, 0, 0]
[0, 2, 1, 0]
[0, 2, 0, 1]
[0, 1, 2, 0]
[0, 1, 1, 1]
[0, 1, 0, 2]
[0, 0, 3, 0]
[0, 0, 2, 1]
[0, 0, 1, 2]
[0, 0, 0, 3]
Количество композиций и время в секундах для простого Python (возможно, массивы с нулевыми значениями) быстрее) для n = 100, и k = 2,3,4,5 (2,8 ГГц Cel-1840)
2 5050 0.040000200271606445
3 171700 0.9900014400482178
4 4421275 20.02204465866089
5 91962520 372.03577995300293
I expect time 2 hours for 100/6 generation
То же самое с массивами numpy (x = np.zeros((n,), dtype=int)
) дает хуже [1116 ] результаты - но, возможно, потому что я не знаю, как их правильно использовать
2 5050 0.07999992370605469
3 171700 2.390003204345703
4 4421275 54.74532389640808
Собственный код (это Delphi, компиляторы C / C ++ могли бы оптимизировать лучше) генерирует 100/6 за 21 секунду
3 171700 0.012
4 4421275 0.125
5 91962520 1.544
6 1609344100 20.748
Невозможно заснуть, пока не будут выполнены все измерения:)
MSVS VC ++: 18 секунд ! (Оптимизация O2)
5 91962520 1.466
6 1609344100 18.283
Итак, 100 миллионов вариантов в секунду. Много времени тратится на проверку пустых ячеек (потому что коэффициент заполнения мал). Скорость, описанная Арндтом, достигается при более высоких коэффициентах k / n и составляет около 300-500 миллионов вариантов в секунду:
n=25, k=15 25140840660 60.981 400 millions per second
По сути, поскольку вы можете реализовать свою валидацию и другую логику в свойстве, вы должны получить доступ через свойство, если у вас нет по конкретной причине - нет.
Это помогает обеспечить согласованность внутри вашего объекта, потому что таким образом вы узнаете, что значения ваших приватных полей прошли через любые суровые условия, которые вы решите использовать в своих методах доступа или сеттера.
С другой стороны, конструктор может быть исключением из этого, потому что вы можете установить начальные значения.
Но в целом, я бы сказал, доступ через свойство.
РЕДАКТИРОВАТЬ
Пример (тривиальный / надуманный)
public class Person
{
private string _name = "";
private List<String> oldnames = new ArrayList();
public string Name
{
get { return _name; }
set
{
oldnames.Add(_name);
_name = value;
}
}
public Person(string name)
{
_name = name; //should I use the property or field here?
}
}
Так что в этом случае вы бы хотели, чтобы конструктор пропустил свойство, но если вы Когда бы вы ни использовали это поле снова, вы будете вызывать ошибку в своем коде, потому что пропускаете «архивирование имени». Причина для проверки в вашем свойстве заключается в том, что вам не нужно дублировать код проверки в каждом месте, к которому вы обращаетесь к полю, поэтому вы не должны пропускать его даже в частных методах.
Я бы порекомендовал использовать собственность, вы никогда не знаете, когда вы могли бы что-то делать внутри вашей собственности, т.е. отложенная загрузка, преобразование, форматирование, вычисления и т. д., которые могут привести к ошибке, если вы используете приватный элемент ...
По большей части это похоже на предпочтение кода, но я предпочитаю использовать публичные или когда-либо частные свойства, вы можете просто добавить некоторая логика для свойства без каких-либо изменений в коде вызывающего. Также в 3.5 .NET у вас есть полезный код сахара как autoproperty.
Может возникнуть ситуация, когда вам потребуется доступ к полю внутренне. Например, когда вы предлагаете только публичный доступ только для чтения к свойству и не указываете значение, которое можно изменять после создания объекта.
public class MyClass
{
private string _MyProperty;
public MyProperty { get { return _MyProperty; } }
public MyClass ()
{
_MyProperty = SomeVeryComplexPropertyInitializationLogic ();
}
}
Обычно я использую общедоступные свойства с некоторыми исключениями, где я могу захотеть избежать любого дополнительного кода, написанного в методе доступа к свойствам. Благодаря автоматическим свойствам в C # 3.0 я редко создаю вспомогательные поля вручную; как правило, только когда значение по умолчанию для поля автоматического резервного копирования не подходит для моего свойства.
Если вы используете имя поля, вы не получите инкапсуляцию. Инкапсуляция применяется не только между классами, но и внутри класса.
Если в какой-то момент в будущем вы переопределите поле, но оставите подписи функции доступа / установщика такими же, не только внешние классы, которые используют ваш класс, не сломаются, но Внутренние процедуры в вашем собственном классе тоже не сломаются.
Возьмем, к примеру, этот код, свободно основанный на коде, который отображается в платформе Apache Wicket (хотя эта среда не страдает этой проблемой; я просто использую ее для иллюстрации):
Допустим, это был оригинальный учебный класс:
class RadioChoice {
private String prefix;
RadioChoice( String prefix ) {
this.prefix = prefix ;
setPrefix( String prefix ) {
this.prefix = prefix ;
}
}
Здесь мы уже видим проблему: та же самая операция this.prefix = prefix
происходит в местах буксировки. Он предназначен для того, чтобы делать одно и то же, но поскольку это происходит в двух местах, это «одно и то же» может расходиться в две разные вещи. (Сравните это с нормализацией базы данных, практикой, предназначенной для предотвращения именно этого.)
Теперь у Apache Wicket есть концепция записи изменений в том, как он отображает веб-страницы, так что эти изменения могут быть отменены. Это делается путем сохранения списка «отмененных» объектов. Префикс RadioChoice - это одна из тех вещей, которые можно отменить, и поэтому установщик 'prefix' должен записать изменение:
class RadioChoice {
private String prefix;
RadioChoice( String prefix ) {
this.prefix = prefix ;
setPrefix( String prefix ) {
// save the old prefix
this.getPage().addChange( new PrefixChange( this.prefix ) );
// set the new one
this.prefix = prefix ;
}
}
Теперь посмотрим, что произойдет: поскольку конструктор устанавливает префикс напрямую, ctor не сохраняет никаких изменений. Если бы мы использовали установщик, ctor бы автоматически " В целом, использование сеттеров и геттеров защищает вас от изменений.
Использовать недвижимость. Или еще лучше, если вы используете C # 3.0 или выше, используйте автоматические свойства, например, так:
public class Person
{
public string Name { get; set; }
public Person(string name)
{
Name = name; //should I use the property or field here?
}
}
Если вы используете свойство сейчас, вы будете готовы, когда измените свой код для использования автоматических свойств.
Вы должны использовать «Имя» (свойство), потому что, если вы хотите проверить это значение, вы можете поместить его в установщик свойства «Name», а затем будет использоваться как для конструктора, так и для последующего задания значения.
По крайней мере в Java нет НИКАКОГО способа использовать открытые поля, потому что старые добрые соглашения javabeans, которые кажутся всем использовать. Я думаю, что C # имеет свойства в качестве конструкций первого языка. Я бы пошел на это
Это зависит. Иногда вы будете писать геттеры / сеттеры, которые выполняют важную предварительную обработку для любого реалистичного взаимодействия с полем. Например, если строковое поле имеет ограничение на то, что оно всегда должно быть в нижнем регистре, то по крайней мере один из ваших методов getter / setter должен вызвать .ToLower () или .ToLowerInvariant (), и в коде вашего класса вы, вероятно, Я хочу использовать это, чтобы убедиться, что ограничение применено.
Однако, также будут времена, когда вам нужно будет обойти эту логику предварительной обработки. Фактически, я видел случаи, когда разработчики непреднамеренно создавали бесконечные циклы, используя открытое свойство, а не приватное поле (извините, я не могу вспомнить пример из головы).
Классы, сгенерированные Linq To SQL, хороший пример, я думаю, потому что они показывают, сколько логики может существовать в свойстве. Попробуйте написать несколько методов расширения, и вы начнете понимать разницу.
Я думаю, суть в том, что это зависит от того, какую логику вы используете в любой заданной точке класса, и какая предварительная обработка существует в методах получения / установки. Если вы когда-либо не уверены или вам кажется, что это не имеет значения, вероятно, лучше использовать свойство getters / setters / public, чтобы вы могли написать более понятный код, который будет следовать ограничениям, добавленным позже.