Проверьте, равно ли значение int 10, 100, 1000,

#c# #numbers

#c# #числа

Вопрос:

У меня есть часть в моем приложении, которая должна что-то делать (=> добавить дополнение 0 перед другими числами), когда указанное число получает дополнительную цифру, что означает, что оно получает 10, 100, 1000 или так далее…

На данный момент я использую для этого следующую логику:

 public static bool IsNewDigit(this int number)
{
    var numberString = number.ToString();
    return numberString.StartsWith("1")
        amp;amp; numberString.Substring(1).All(c => c == '0');
}
  

Я могу сделать:

 if (number.IsNewDigit()) { /* add padding 0 to other numbers */ }
  

Мне это кажется «взломом» с использованием преобразования строк.
Есть ли что-то лучшее (может быть, даже «встроенное») для этого?

Обновить:
Один из примеров, когда мне это нужно:
у меня есть элемент со следующей (упрощенной) структурой:

 public class Item
{
    public int Id { get; set; }
    public int ParentId { get; set; }
    public int Position { get; set; }
    public string HierarchicPosition { get; set; }
}
  

HierarchicPosition — это собственная позиция (с дополнением) и родительские HierarchicPositon элементы. Например. элемент, который является 3-м дочерним элементом из 12 из элемента в позиции 2, имеет 2.03 в качестве своего HierarchicPosition . Это также может быть что-то более сложное, например 011.7.003.2.02 .
Затем это значение используется для очень простой сортировки элементов в «древовидной» структуре.

Теперь у меня есть IQueryable<Item> и хочу добавить один элемент в качестве последнего дочернего элемента другого элемента. Чтобы избежать необходимости воссоздавать все HierarchicalPosition , что я хотел бы обнаружить (с учетом рассматриваемой логики), если новая позиция добавляет новую цифру:

 Item newItem = GetNewItem();
IQueryable<Item> items = db.Items;
var maxPosition = items.Where(i => i.ParentId == newItem.ParentId)
                       .Max(i => i.Position);
newItem.Position = maxPosition   1;
if (newItem.Position.IsNewDigit())
    UpdateAllPositions(items.Where(i => i.ParentId == newItem.ParentId));
else
    newItem.HierarchicPosition = GetHierarchicPosition(newItem);
  

ОБНОВЛЕНИЕ # 2:
Я запрашиваю эту строку позиции из базы данных, например:

 var items = db.Items.Where(...)
              .OrderBy(i => i.HierarchicPosition)
              .Skip(pageSize * pageNumber).Take(pageSize);
  

Из-за этого я не могу использовать an IComperator (или что-то еще, что сортируется «через код»).
Это вернет элементы с HierarchicPosition like ( pageSize = 10 ):

03.04
03.05
04
04.01
04.01.01
04.01.02
04.02
04.02.01
04.03
05

ОБНОВЛЕНИЕ # 3:
Мне нравится альтернативное решение со double значениями, но у меня есть несколько «более сложных случаев», таких как следующие, я не уверен, что смогу решить это:
я создаю (на части многих) галерею изображений, в которой есть Categories и Images . Там у категории может быть родитель и несколько дочерних элементов, и каждое изображение принадлежит категории (я назвал их Holder и Asstes в моей логике — поэтому у каждого изображения есть держатель, и каждая категория может иметь несколько активов). Эти изображения сортируются сначала по позиции категорий, а затем по собственной позиции. Это я делаю, комбинируя HierarchicPosition подобное HolderHierarchicPosition#ItemHierarchicPosition . Таким образом, в категории, которая имеет 02.04 в качестве своей позиции и 120 изображений, будет получено 3-е изображение 02.04#003 .
У меня есть даже несколько случаев с «тремя уровнями» (или, может быть, больше в будущем), например 03.1#02#04 .
Могу ли я адаптировать «двойное решение» для поддержки таких сценариев?

PS: Я также открыт для другого решения моей базовой проблемы.

Комментарии:

1. Я не понял вашего вопроса. можете ли вы предоставить некоторые примеры входных данных и желаемых результатов? 🙂

2. У вас есть доступ к «предыдущему» номеру?

3. Как насчет использования Math.Log10 метода ? Вы можете проверить, равен результат int или нет, например.. Это не удается только 1 для вашего примера.

4. return number.ToString().Length > (number - 1).ToString().Length;

5. Если вы выполняете только заполнение, почему бы вам не использовать одну из функций форматирования чисел ToString("D4") ?;

Ответ №1:

Вы могли бы проверить, является ли логарифм числа по основанию 10 целым числом. (10 -> 1, 100 -> 2, 1000 -> 3, …)

Это также может немного упростить ваш алгоритм в целом. Вместо того, чтобы добавлять один 0 заполнения каждый раз, когда вы находите что-то большее, просто отслеживайте максимальное число, которое вы видите, затем возьмите length = floor(log10(number)) 1 и убедитесь, что все дополнено length . Эта часть не страдает от арифметических проблем с плавающей запятой, таких как сравнение с целым числом.

Комментарии:

1. довольно хрупкий. Выполнение F(x) == 1.0 ненадежно.

2. Верно, но оно верно / согласовано в пределах известного диапазона — просто проверьте его до MAX_INT раньше — оно соответствует.

Ответ №2:

Из того, что вы описываете, похоже, что ваша HierarchicPosition позиция должна поддерживать порядок элементов, и вы сталкиваетесь с проблемой, что, когда у вас есть идентификаторы 1..9 и добавьте a 10 , вы 1,10,2,3,4,5,6... где-то получите порядок и, следовательно, захотите 01,02,03...,10 исправить-слева направо?

Если я прав, пожалуйста, сначала взгляните на это: https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem

Потому что то, что вы пытаетесь сделать, является обходным путем для решения проблемы определенным образом. — Но могут быть более эффективные способы действительно решить эту проблему. (поэтому вам следовало бы лучше спросить о вашей реальной проблеме, а не о решении, которое вы пытаетесь реализовать)

Смотрите Здесь решение, используя пользовательский IComparator для сортировки строк (которые на самом деле являются числами) обычным способом: http://www.codeproject.com/Articles/11016/Numeric-String-Sort-in-C


Обновление, касающееся вашего обновления:

Предоставляя сортирующую «строку», как вы это делаете, вы можете вставить элемент «где-нибудь» без переиндексации ВСЕХ последующих элементов, как это было бы для целочисленного значения. (Похоже, это и есть цель)

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

Если вы вставляете элемент где-то между 2 существующими элементами, все, что вам нужно сделать, это: this.sortingValue = (prior.sortingValue next.sortingValue) / 2 и обрабатывать регистр при вставке в конец списка.

Предположим, вы добавляете элементы в следующем порядке:

 1 First Element // pick a double value for sorting - 100.00 for example. -> 100.00
2 Next Element // this is the list end - lets just add another 100.00 -> 200.00
1.1 Child // this should go "in between": (100 200)/2 = 150.00
1.2 Another // between 1.1 and 2 : (150 200)/2 = 175
  

Когда вы теперь выполняете простую сортировку в зависимости от этого двойного поля, порядок будет:

 100.00 -> 1
150.00 -> 1.1
175.00 -> 1.2
200.00 -> 2
  

Хотите добавить 1.1.1 ? Отлично: positon = (150.00 175.00)/2; ;

вы могли бы просто умножить все на 10, всякий раз, когда ваше НОВОЕ значение достигает x.5 *, чтобы убедиться, что у вас не заканчиваются десятичные разряды (но вам не нужно — наличие .5 .25 .125 ... не повредит сортировке):

Итак, после добавления 1.1.1 значения, которое будет 162,5 , умножьте все на 10:

 1000.00 -> 1
1500.00 -> 1.1
1625.00 -> 1.1.1
1750.00 -> 1.2
2000.00 -> 2
  

Итак, всякий раз, когда вы перемещаете элемент вокруг, вам нужно только пересчитать положение n , посмотрев на n-1 и n 1

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


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


Решение с «двойными» значениями имеет некоторые ограничения, но будет работать для небольших наборов групп. Однако вы говорите о «Группах, подгруппах и изображениях с количеством 100», поэтому предпочтительнее другое решение:

  • Во-первых, вам следует реорганизовать свою базу данных: в настоящее время вы пытаетесь «сжать» дерево в список (таблицы данных — это в основном списки)
  • Чтобы действительно отразить сложную компоновку дерева с бесконечной глубиной, вы должны использовать 2 таблицы и реализовать composite pattern .
  • Затем вы можете использовать рекурсивный подход, чтобы получить категорию, ее подкатегорию, […] и, наконец, элементы этой категории.
  • При этом вам нужно только указать положение каждого листа в его текущем узле.
  • Перестановка листьев не повлияет ни на один лист другого узла или любого узла.
  • Перераспределение узлов не повлияет ни на один подузел или лист этого узла.

Комментарии:

1. you'll get the order 1,10,2,3,4,5,6... somewhere and therefore want to pad-left to 01,02,03...,10 - correct? Да, это основная проблема. Я посмотрю на предложенные вами ссылки…

2. Я не могу использовать пользовательский IComperator , поскольку я выполняю эту сортировку (и подкачку) «в БД» — я добавлю это к вопросу.

3. @chrfin почему бы не изменить «HierarchicPosition» на целочисленное значение? Они могут быть отсортированы без каких-либо усилий.

4. Потому что у меня не может быть «нескольких уровней» (см. Пример в вопросе) в «одном целом числе».

5. ЭТО хорошо — мне нужно проверить это с помощью моего «самого сложного варианта использования» (см. Обновление # 3 к вопросу)…

Ответ №3:

Вы можете проверить сумму квадратов всех цифр для ввода, 10,100,1000 имеет нечто общее, что, если вы вычисляете сумму квадратов всех цифр, она должна сходиться к единице;

10
1^2 0^2 = 1
100
1^2 0^2 0^2 = 1

и так далее и тому подобное.