MySQL-Version (кредиты @Gordon Linoff)
SELECT
ID
FROM
<table>
GROUP BY
ID
HAVING
SUM(IF(day(DUE_DT + interval 1 Day) = 1, 1, 0)) = COUNT(ID);
Исходный ответ:
SELECT MAX(DUE_DT) FROM <table> WHERE ID = <the desired ID>
или если вы хотите все MAX ( DUE_DT) для каждого уникального идентификатора
SELECT ID, MAX(DATE) FROM <table> GROUP BY ID
В документации для String.Split есть несколько полезных замечаний, относящихся к этой проблеме, хотя перед тем, как это обнаружить, я написал следующее.
Один из способов сделать это - найти разделитель с помощью метода String.IndexOf - вы можете указать индекс, с которого начинается поиск, так что можно пропустить пункты без необходимости просматривать каждый персонаж. (Проверка каждого символа происходит за кулисами, но это немного быстрее, чем делать это самостоятельно.)
Я придумал метод расширения, добавив новый класс с именем "ExtensionMethods.cs" в решение с помощью это содержание:
namespace ExtensionMethods
{
public static class MyExtensions
{
/// <summary>
/// Get the nth item from a delimited string.
/// </summary>
/// <param name="s">The string to retrieve a delimited item from.</param>
/// <param name="delimiter">The character used as the item delimiter.</param>
/// <param name="n">Zero-based index of item to return.</param>
/// <returns>The nth item or an empty string.</returns>
public static string Split(this string s, char delimiter, int n)
{
int pos = pos = s.IndexOf(delimiter);
if (n == 0 || pos < 0)
{ return (pos >= 0) ? s.Substring(0, pos) : s; }
int nDelims = 1;
while (nDelims < n && pos >= 0)
{
pos = s.IndexOf(delimiter, pos + 1);
nDelims++;
}
string result = "";
if (pos >= 0)
{
int nextDelim = s.IndexOf(delimiter, pos + 1);
result = (nextDelim < 0) ? s.Substring(pos + 1) : s.Substring(pos + 1, nextDelim - pos - 1);
}
return result;
}
}
}
И небольшая программа для его проверки:
using System;
using System.Diagnostics;
using System.Linq;
using ExtensionMethods;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
// test data...
string s = string.Join(";", Enumerable.Range(65, 26).Select(c => (char)c));
s = s.Insert(3, ";;;");
string o = "";
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 1; i <= 1000000; i++) {
o = s.Split(';', 21);
}
sw.Stop();
Console.WriteLine("Item directly selected: " + sw.ElapsedMilliseconds);
sw.Restart();
for (int i = 1; i <= 1000000; i++) {
o = s.Split(';')[21];
}
sw.Stop();
Console.WriteLine("Item from split array: " + sw.ElapsedMilliseconds + "\r\n");
Console.WriteLine(s);
Console.WriteLine(o);
Console.ReadLine();
}
}
}
Пример вывода:
Элемент, выбранный напрямую: 1016
[ 115] Элемент из разделенного массива: 1345A; B ;;;; C; D; E; F; G; H; I; J; K; L; M; N; O; P; Q ; R; S; T; U; V; W; X; Y; Z
blockquote>
S
Ссылка: Как выполнить и вызвать a Пользовательский метод расширения (Руководство по программированию в C #)
попробуйте это:
public static string MyExtension(this string s, char delimiter, int n)
{
var begin = n== 0 ? 0 : Westwind.Utilities.StringUtils.IndexOfNth(s, delimiter, n);
if (begin == -1)
return null;
var end = s.IndexOf(delimiter, begin + (n==0?0:1));
if (end == -1 ) end = s.Length;
//var end = Westwind.Utilities.StringUtils.IndexOfNth(s, delimiter, n + 1);
var result = s.Substring(begin +1, end - begin -1 );
return result;
}
PS: используется библиотека Westwind.Utilities
Код теста:
void Main()
{
string s = string.Join(";", Enumerable.Range(65, 26).Select(c => (char)c));
s = s.Insert(3, ";;;");
string o = "";
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 1; i <= 1000000; i++) {
o = s.Split(';', 21);
}
sw.Stop();
Console.WriteLine("Item directly selected: " + sw.ElapsedMilliseconds);
sw.Restart();
for (int i = 1; i <= 1000000; i++) {
o = s.MyExtension(';', 21);
}
sw.Stop();
Console.WriteLine("Item directly selected by MyExtension: " + sw.ElapsedMilliseconds);
sw.Restart();
for (int i = 1; i <= 1000000; i++) {
o = s.Split(';')[21];
}
sw.Stop();
Console.WriteLine("Item from split array: " + sw.ElapsedMilliseconds + "\r\n");
Console.WriteLine(s);
Console.WriteLine(o);
}
public static class MyExtensions
{
/// <summary>
/// Get the nth item from a delimited string.
/// </summary>
/// <param name="s">The string to retrieve a delimited item from.</param>
/// <param name="delimiter">The character used as the item delimiter.</param>
/// <param name="n">Zero-based index of item to return.</param>
/// <returns>The nth item or an empty string.</returns>
public static string Split(this string s, char delimiter, int n)
{
int pos = pos = s.IndexOf(delimiter);
if (n == 0 || pos < 0)
{ return (pos >= 0) ? s.Substring(0, pos) : s; }
int nDelims = 1;
while (nDelims < n && pos >= 0)
{
pos = s.IndexOf(delimiter, pos + 1);
nDelims++;
}
string result = "";
if (pos >= 0)
{
int nextDelim = s.IndexOf(delimiter, pos + 1);
result = (nextDelim < 0) ? s.Substring(pos + 1) : s.Substring(pos + 1, nextDelim - pos - 1);
}
return result;
}
public static string MyExtension(this string s, char delimiter, int n)
{
var begin = n== 0 ? 0 : Westwind.Utilities.StringUtils.IndexOfNth(s, delimiter, n);
if (begin == -1)
return null;
var end = s.IndexOf(delimiter, begin + (n==0?0:1));
if (end == -1 ) end = s.Length;
//var end = Westwind.Utilities.StringUtils.IndexOfNth(s, delimiter, n + 1);
var result = s.Substring(begin +1, end - begin -1 );
return result;
}
}
Результаты:
[ 112]Редактировать: Благодаря @Kalten я улучшил решение еще больше. Значительные различия были замечены в результатах тестов.
Используя следующее регулярное выражение: ^([^;]*;){21}(.*?);
, при этом вам не нужно генерировать список разделенных дыр для поиска желаемой позиции, и как только вы достигнете ее, это будет зависеть от того, существует или нет.
Объяснение :
^ --> start of a line.
([^;]*;){Position - 1} --> notice that the symbol ; here is the delimiter, the expression will loop Pos - 1 times
(.*?) --> Non-Greedy .*
Подробнее о регулярных выражениях на C #: документация [1111 ]
В приведенном ниже примере я реализовал два примера, чтобы показать вам, как это работает.
Метод сопоставления : документация (в основном он ищет только первое вхождение шаблона) RegexOptions.Singleline : Обрабатывает входные данные как сигнальную линию.
Код C #
Console.WriteLine("First Delimiter : ");
int Position = 22;
char delimiter = ',';
string pattern = @"^([^" + delimiter + "]*" + delimiter + "){" + (Position - 1) + @"}(.*?)" + delimiter;
Regex regex = new Regex(pattern, RegexOptions.Singleline);
// First Example
string Data = @"AAV,zzz,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22ABC,23,24,24";
Match Re = regex.Match(Data);
if (Re.Groups.Count > 0)
Console.WriteLine("\tMatch found : " + Re.Groups[2]);
// Second Example
Console.WriteLine("Second Delimiter : ");
Position = 8;
delimiter = ';';
pattern = @"^([^" + delimiter + "]*" + delimiter + "){" + (Position - 1) + @"}(.*?)" + delimiter;
Data = @"61d2e3f6-bcb7-4cd1-a81e-4f8f497f0da2;0;192.100.0.102:4362;2014-02-14;283;0;354;23;0;;;""0x8D15A2913C934DE"";Thursday, 19-Jun-14 22:58:10 GMT;";
regex = new Regex(pattern, RegexOptions.Singleline);
Re = regex.Match(Data);
if (Re.Groups.Count > 0)
Console.WriteLine("\tMatch found : " + Re.Groups[2]);
Вывод:
Первый разделитель:
Match found : 22ABC
Второй разделитель:
[ 113] blockquote>
Слишком поздно для «ответа», но этот код дает мне время выполнения около 0,75 секунд с обеими строками, обработанными 1 000 000 раз. Разница на этот раз в том, что теперь я не маршалирую объект, а использую указатели.
И на этот раз я возвращаю одну новую строку (String.Substring).
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
class Program
{
static void Main(string[] args)
{
string testString1 = "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24";
string testString2 = "61d2e3f6-bcb7-4cd1-a81e-4f8f497f0da2;0;192.100.0.102:4362;2014-02-14;283;0;354;23;0;;;\"0x8D15A2913C934DE\";Thursday, 19-Jun-14 22:58:10 GMT;";
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 1; i < 1000000; i++)
{
Delimit(testString1, ',', 22);
Delimit(testString2, ';', 6);
}
sw.Stop();
Console.WriteLine($"==>{sw.ElapsedMilliseconds}");
Console.ReadLine();
}
static string Delimit(string stringUnderTest, char delimiter, int skipCount)
{
const int SIZE_OF_UNICHAR = 2;
int i = 0;
int index = 0;
char c = Char.MinValue;
GCHandle handle = GCHandle.Alloc(stringUnderTest, GCHandleType.Pinned);
try
{
IntPtr ptr = handle.AddrOfPinnedObject();
for (i = 0; i < skipCount; i++)
while ((char)Marshal.ReadByte(ptr, index += SIZE_OF_UNICHAR) != delimiter) ;
i = index;
while ((c = (char)Marshal.ReadByte(ptr, i += SIZE_OF_UNICHAR)) != delimiter) ;
}
finally
{
if (handle.IsAllocated)
handle.Free();
}
return stringUnderTest.Substring((index + SIZE_OF_UNICHAR) >> 1, (i - index - SIZE_OF_UNICHAR) >> 1);
}
}
Если вы хотите быть уверены, что код анализирует строку только за один проход, и анализирует только то, что нужно, вы можете написать процедуру, которая перебирает строку самостоятельно.
Поскольку все строки c # реализуют IEnumerable<char>
, довольно просто разработать метод, который требует нулевого выделения строк:
static public IEnumerable<char> GetDelimitedField(this IEnumerable<char> source, char delimiter, int index)
{
foreach (var c in source)
{
if (c == delimiter)
{
if (--index < 0) yield break;
}
else
{
if (index == 0) yield return c;
}
}
}
Возвращает результат как IEnumerable<char>
, но его дешево преобразовать в строка. В любом случае это будет намного более короткая строка.
static public string GetDelimitedString(this string source, char delimiter, int index)
{
var result = source.GetDelimitedField(delimiter, index);
return new string(result.ToArray());
}
И вы можете назвать это так:
var input ="Zero,One,Two,Three,Four,Five,Six";
var output = input.GetDelimitedString(',',5);
Console.WriteLine(output);
Вывод:
Five