Для тех, кто не знает, как использовать PDO (исходя из функций В основном читайте mysql_
), я сделал очень, очень простую PDO-обертку , которая представляет собой один файл. Он существует, чтобы показать, насколько легко выполнять все обычные приложения, которые необходимо выполнить. Работает с PostgreSQL, MySQL и SQLite.
Мне нужен один столбец
$count = DB::column('SELECT COUNT(*) FROM `user`);
Мне нужны результаты массива (key => value) (т. е. для создания selectbox)
$pairs = DB::pairs('SELECT `id`, `username` FROM `user`);
Мне нужен результат одной строки
$user = DB::row('SELECT * FROM `user` WHERE `id` = ?', array($user_id));
Мне нужен массив результатов
$banned_users = DB::fetch('SELECT * FROM `user` WHERE `banned` = ?', array(TRUE));
Попробуйте следующий код.
public static IList<IList<T>> Split<T>(IList<T> source)
{
return source
.Select((x, i) => new { Index = i, Value = x })
.GroupBy(x => x.Index / 3)
.Select(x => x.Select(v => v.Value).ToList())
.ToList();
}
идея состоит в том, чтобы сначала сгруппировать элементы индексами. Деление на три имеет эффект группировки их в группы 3. Тогда преобразуйте каждую группу в список и IEnumerable
из List
к List
из List
s
Если список имеет тип system.collections.generic, можно использовать метод "CopyTo", доступный для копирования элементов массива к другим массивам sub. Вы определяете элемент запуска и число элементов для копирования.
Вы могли также сделать 3 клона своего исходного списка и использовать "RemoveRange" в каждом списке для уменьшения списка к размеру, который Вы хотите.
Или просто создают вспомогательный метод сделать это для Вас.
Вот список, разделяющий стандартную программу, которую я записал паре несколько месяцев назад:
public static List<List<T>> Chunk<T>(
List<T> theList,
int chunkSize
)
{
List<List<T>> result = theList
.Select((x, i) => new {
data = x,
indexgroup = i / chunkSize
})
.GroupBy(x => x.indexgroup, x => x.data)
.Select(g => new List<T>(g))
.ToList();
return result;
}
Вы могли использование много запросов, которые используют Take
и Skip
, но это добавило бы слишком много повторений в исходном списке, я верю.
Скорее я думаю, что необходимо создать собственный итератор, как так:
public static IEnumerable<IEnumerable<T>> GetEnumerableOfEnumerables<T>(
IEnumerable<T> enumerable, int groupSize)
{
// The list to return.
List<T> list = new List<T>(groupSize);
// Cycle through all of the items.
foreach (T item in enumerable)
{
// Add the item.
list.Add(item);
// If the list has the number of elements, return that.
if (list.Count == groupSize)
{
// Return the list.
yield return list;
// Set the list to a new list.
list = new List<T>(groupSize);
}
}
// Return the remainder if there is any,
if (list.Count != 0)
{
// Return the list.
yield return list;
}
}
можно тогда назвать это, и это - LINQ, включенный так, можно выполнить другие операции на получающихся последовательностях.
<час>световой сигнал In [1 123] ответ Sam , который я чувствовал, был более легкий способ сделать это без:
Однако здесь является другой передачей, которую я шифровал в дополнительном методе к [1 124] IEnumerable<T>
названный Chunk
:
public static IEnumerable<IEnumerable<T>> Chunk<T>(this IEnumerable<T> source,
int chunkSize)
{
// Validate parameters.
if (source == null) throw new ArgumentNullException("source");
if (chunkSize <= 0) throw new ArgumentOutOfRangeException("chunkSize",
"The chunkSize parameter must be a positive value.");
// Call the internal implementation.
return source.ChunkInternal(chunkSize);
}
Ничто удивляющее там, просто основная проверка ошибок.
Хождение дальше к [1 110]:
private static IEnumerable<IEnumerable<T>> ChunkInternal<T>(
this IEnumerable<T> source, int chunkSize)
{
// Validate parameters.
Debug.Assert(source != null);
Debug.Assert(chunkSize > 0);
// Get the enumerator. Dispose of when done.
using (IEnumerator<T> enumerator = source.GetEnumerator())
do
{
// Move to the next element. If there's nothing left
// then get out.
if (!enumerator.MoveNext()) yield break;
// Return the chunked sequence.
yield return ChunkSequence(enumerator, chunkSize);
} while (true);
}
В основном, это получает IEnumerator<T>
и вручную выполняет итерации через каждый объект. Это проверяет, чтобы видеть если там любые объекты в настоящее время, чтобы быть перечисленным. После того, как каждый блок перечисляется через, при отсутствии оставленных объектов, он вспыхивает.
, Как только это обнаруживает, существуют объекты в последовательности, это делегирует ответственность за внутреннее IEnumerable<T>
реализация к [1 113]:
private static IEnumerable<T> ChunkSequence<T>(IEnumerator<T> enumerator,
int chunkSize)
{
// Validate parameters.
Debug.Assert(enumerator != null);
Debug.Assert(chunkSize > 0);
// The count.
int count = 0;
// There is at least one item. Yield and then continue.
do
{
// Yield the item.
yield return enumerator.Current;
} while (++count < chunkSize && enumerator.MoveNext());
}
С тех пор MoveNext
был уже назван на эти IEnumerator<T>
, передал [1 116], это приводит к объекту, возвращенному [1 127] Current
, и затем увеличивает количество, удостоверяясь никогда не возвращать [больше чем 1 118] объекты и перемещаясь в следующий объект в последовательности после каждого повторения (но закороченный, если количество объектов, к которым приводят, превышает размер блока).
, Если не будет никаких оставленных объектов, то InternalChunk
метод сделает другую передачу во внешнем цикле, но когда MoveNext
будет назван во второй раз, это все еще возвратит false, согласно документации (шахта акцента):
, Если MoveNext передает конец набора, перечислитель расположен после того, как последний элемент в наборе и MoveNext возвращает false. , Когда перечислитель в этом положении, последующие вызовы к MoveNext также возвращают false, пока Сброс не называют.
На данном этапе цикл повредится, и последовательность последовательностей завершится.
Это - простой тест:
static void Main()
{
string s = "agewpsqfxyimc";
int count = 0;
// Group by three.
foreach (IEnumerable<char> g in s.Chunk(3))
{
// Print out the group.
Console.Write("Group: {0} - ", ++count);
// Print the items.
foreach (char c in g)
{
// Print the item.
Console.Write(c + ", ");
}
// Finish the line.
Console.WriteLine();
}
}
Вывод:
Group: 1 - a, g, e,
Group: 2 - w, p, s,
Group: 3 - q, f, x,
Group: 4 - y, i, m,
Group: 5 - c,
важное примечание, это будет не работа, если Вы не истощите всю дочернюю последовательность или повреждение ни в какой точке в родительской последовательности. Это - важный протест, но если Ваш вариант использования будет то, что Вы используете каждый элемент последовательности последовательностей, тогда это будет работать на Вас.
Кроме того, это сделает странные вещи, если Вы будете играть с порядком, так же, как [1 129], Sam сделал однажды .
Проверьте это! У меня есть список элементов со счетчиком последовательности и датой. В течение каждого раза перезапуски последовательности я хочу создать новый список.
Напр. список сообщений.
List<dynamic> messages = new List<dynamic>
{
new { FcntUp = 101, CommTimestamp = "2019-01-01 00:00:01" },
new { FcntUp = 102, CommTimestamp = "2019-01-01 00:00:02" },
new { FcntUp = 103, CommTimestamp = "2019-01-01 00:00:03" },
//restart of sequence
new { FcntUp = 1, CommTimestamp = "2019-01-01 00:00:04" },
new { FcntUp = 2, CommTimestamp = "2019-01-01 00:00:05" },
new { FcntUp = 3, CommTimestamp = "2019-01-01 00:00:06" },
//restart of sequence
new { FcntUp = 1, CommTimestamp = "2019-01-01 00:00:07" },
new { FcntUp = 2, CommTimestamp = "2019-01-01 00:00:08" },
new { FcntUp = 3, CommTimestamp = "2019-01-01 00:00:09" }
};
я хочу разделить список на отдельные списки как встречные перезапуски. Вот код:
var arraylist = new List<List<dynamic>>();
List<dynamic> messages = new List<dynamic>
{
new { FcntUp = 101, CommTimestamp = "2019-01-01 00:00:01" },
new { FcntUp = 102, CommTimestamp = "2019-01-01 00:00:02" },
new { FcntUp = 103, CommTimestamp = "2019-01-01 00:00:03" },
//restart of sequence
new { FcntUp = 1, CommTimestamp = "2019-01-01 00:00:04" },
new { FcntUp = 2, CommTimestamp = "2019-01-01 00:00:05" },
new { FcntUp = 3, CommTimestamp = "2019-01-01 00:00:06" },
//restart of sequence
new { FcntUp = 1, CommTimestamp = "2019-01-01 00:00:07" },
new { FcntUp = 2, CommTimestamp = "2019-01-01 00:00:08" },
new { FcntUp = 3, CommTimestamp = "2019-01-01 00:00:09" }
};
//group by FcntUp and CommTimestamp
var query = messages.GroupBy(x => new { x.FcntUp, x.CommTimestamp });
//declare the current item
dynamic currentItem = null;
//declare the list of ranges
List<dynamic> range = null;
//loop through the sorted list
foreach (var item in query)
{
//check if start of new range
if (currentItem == null || item.Key.FcntUp < currentItem.Key.FcntUp)
{
//create a new list if the FcntUp starts on a new range
range = new List<dynamic>();
//add the list to the parent list
arraylist.Add(range);
}
//add the item to the sublist
range.Add(item);
//set the current item
currentItem = item;
}
public static List<List<T>> GetSplitItemsList<T>(List<T> originalItemsList, short number)
{
var listGroup = new List<List<T>>();
int j = number;
for (int i = 0; i < originalItemsList.Count; i += number)
{
var cList = originalItemsList.Take(j).Skip(i).ToList();
j += number;
listGroup.Add(cList);
}
return listGroup;
}
Мы обнаружили, что решение Дэвида Б работает лучше всего. Но мы адаптировали его к более общему решению:
list.GroupBy(item => item.SomeProperty)
.Select(group => new List<T>(group))
.ToArray();