Скажем, у меня есть List<string> listOfStrings
, и я хочу разделить этот список на два списка на основе некоторого предиката. Например, первый список должен содержать все строки, начинающиеся с буквы, а второй — список строк, которые не начинаются.
Теперь я бы сделал это так:
var firstList = listOfStrings.Where(str => predicate(str));
var secondList = listOfStrings.Where(str => !predicate(str));
Есть ли лучший способ сделать это в одну строку?
Вы можете использовать Linq GroupBy()
:
var splitted = listOfStrings.GroupBy(s => Char.IsLetter(s[0]));
А с вашим predicate
это будет:
Func<string, bool> predicate;
var splitted = listOfStrings.GroupBy(predicate);
Применение:
Самый простой способ — преобразовать сгруппированные данные в Dictionary<bool, IEnumerable<string>>
, когда ключ — это bool
, обозначающий, начинаются ли элементы в нем с буквы:
var splitted = list.GroupBy(x => Char.IsLetter(x[0]))
.ToDictionary(x => x.Key, z => z.ToArray());
var startWithLetter = splitted[true];
var dontStartWithLetter = splitted[false];
Конечно, есть много способов преобразовать данные в желаемую структуру, но, на мой взгляд, вышеизложенное довольно лаконично.
См. MSDN
@eddyP23, Готово.
Вы можете использовать «GroupBy» или «ToLookup», в зависимости от того, что вы будете делать с результатами. Проверьте также поиск против группового
Я бы сделал что-то вроде этого:
class Program
{
static void Main(string[] args)
{
Func<string, bool> startsWithA = s => s[0] == 'a';
List<string> listOfStrings = new List<string>()
{
"abc",
"acb",
"bac",
"bca",
"cab",
"cba"
};
Dictionary<bool, List<string>> dictionaryOfListsOfStrings = listOfStrings.GroupBy(startsWithA).ToDictionary(x => x.Key, x => x.ToList());
}
}
В Kotlin есть функция раздел (источники). С# версия:
var (first, second) = list.Partition(x => x.IsTrue);
Расширение:
public static (IEnumerable<T> first, IEnumerable<T> second) Partition<T>(this IEnumerable<T> list, Func<T, bool> predicate)
{
var lookup = list.ToLookup(predicate);
return (lookup[true], lookup[false]);
}
Может быть удобнее вернуть List<T>
или использовать GroupBy или что-то еще, в зависимости от варианта использования.
Спасибо, но для полноты картины, не могли бы вы добавить пример извлечения обоих списков из
splitted
?