Necromancing. Если используется поставщик LINQ, основанный на базе данных, может быть записано значительно более читаемое левое внешнее соединение:
from maintable in Repo.T_Whatever
from xxx in Repo.T_ANY_TABLE.Where(join condition).DefaultIfEmpty()
Если вы опустите DefaultIfEmpty()
, у вас будет внутреннее соединение.
Возьмите принятый ответ:
from c in categories
join p in products on c equals p.Category into ps
from p in ps.DefaultIfEmpty()
Этот синтаксис очень сбивает с толку, и неясно, как это работает, когда вы хотите уйти, чтобы присоединиться к таблицам MULTIPLE.
Примечание. Следует отметить, что from alias in Repo.whatever.Where(condition).DefaultIfEmpty()
является таким же, как внешний-apply / left-join-lateral, который любой (не отсталый) оптимизатор базы данных отлично способен перевести в левое соединение , до тех пор, пока вы не вводите значения строк (например, фактическое внешнее применение). Не делайте этого в Linq-2-Objects (потому что при использовании Linq-to-Objects нет DB-оптимизатора).
Подробный пример
var query2 = (
from users in Repo.T_User
from mappings in Repo.T_User_Group
.Where(mapping => mapping.USRGRP_USR == users.USR_ID)
.DefaultIfEmpty() // <== makes join left join
from groups in Repo.T_Group
.Where(gruppe => gruppe.GRP_ID == mappings.USRGRP_GRP)
.DefaultIfEmpty() // <== makes join left join
// where users.USR_Name.Contains(keyword)
// || mappings.USRGRP_USR.Equals(666)
// || mappings.USRGRP_USR == 666
// || groups.Name.Contains(keyword)
select new
{
UserId = users.USR_ID
,UserName = users.USR_User
,UserGroupId = groups.ID
,GroupName = groups.Name
}
);
var xy = (query2).ToList();
При использовании с LINQ 2 SQL он хорошо переведёт на следующий очень читаемый SQL-запрос:
SELECT
users.USR_ID AS UserId
,users.USR_User AS UserName
,groups.ID AS UserGroupId
,groups.Name AS GroupName
FROM T_User AS users
LEFT JOIN T_User_Group AS mappings
ON mappings.USRGRP_USR = users.USR_ID
LEFT JOIN T_Group AS groups
ON groups.GRP_ID == mappings.USRGRP_GRP
Редактировать:
См. Также & quot; Конвертировать запрос SQL Server в запрос Linq & quot; для более сложного примера.
Кроме того, если вы делаете это в Linq-2-Objects (вместо Linq-2-SQL), вы должны сделать это старомодно (потому что LINQ to SQL правильно это переводит для присоединения операции, но над объектами этот метод заставляет полностью сканировать и не использует поиск по индексу, почему ...):
var query2 = (
from users in Repo.T_Benutzer
join mappings in Repo.T_Benutzer_Benutzergruppen on mappings.BEBG_BE equals users.BE_ID into tmpMapp
join groups in Repo.T_Benutzergruppen on groups.ID equals mappings.BEBG_BG into tmpGroups
from mappings in tmpMapp.DefaultIfEmpty()
from groups in tmpGroups.DefaultIfEmpty()
select new
{
UserId = users.BE_ID
,UserName = users.BE_User
,UserGroupId = mappings.BEBG_BG
,GroupName = groups.Name
}
);
Итерируйте свой список в обратном порядке с помощью цикла for:
for (int i = safePendingList.Count - 1; i >= 0; i--)
{
// some code
// safePendingList.RemoveAt(i);
}
Пример:
var list = new List<int>(Enumerable.Range(1, 10));
for (int i = list.Count - 1; i >= 0; i--)
{
if (list[i] > 5)
list.RemoveAt(i);
}
list.ForEach(i => Console.WriteLine(i));
В качестве альтернативы вы можете использовать метод RemoveAll с предикатом для проверки:
safePendingList.RemoveAll(item => item.Value == someValue);
Вот упрощенный пример для демонстрации:
var list = new List<int>(Enumerable.Range(1, 10));
Console.WriteLine("Before:");
list.ForEach(i => Console.WriteLine(i));
list.RemoveAll(i => i > 5);
Console.WriteLine("After:");
list.ForEach(i => Console.WriteLine(i));
Проследите элементы, которые будут удалены со свойством и удалите их всех после процесса.
using System.Linq;
List<MyProperty> _Group = new List<MyProperty>();
// ... add elements
bool cond = true;
foreach (MyProperty currObj in _Group)
{
if (cond)
{
// SET - element can be deleted
currObj.REMOVE_ME = true;
}
}
// RESET
_Group.RemoveAll(r => r.REMOVE_ME);
Просто требуемый для добавления моих 2 центов к этому в случае, если это помогает любому я имел подобную проблему, но должен был удалить несколько элементов из списка массива, в то время как это выполнялось с помощью итераций. самый высокий ответ upvoted сделал это для меня по большей части, пока я не столкнулся с ошибками и понял, что индекс был больше, чем размер списка массива в некоторых случаях, потому что несколько элементов удалялись, но индекс цикла не отслеживал это. Я зафиксировал это с простой проверкой:
ArrayList place_holder = new ArrayList();
place_holder.Add("1");
place_holder.Add("2");
place_holder.Add("3");
place_holder.Add("4");
for(int i = place_holder.Count-1; i>= 0; i--){
if(i>= place_holder.Count){
i = place_holder.Count-1;
}
// some method that removes multiple elements here
}
Я сделал бы как это
using System.IO;
using System;
using System.Collections.Generic;
class Author
{
public string Firstname;
public string Lastname;
public int no;
}
class Program
{
private static bool isEven(int i)
{
return ((i % 2) == 0);
}
static void Main()
{
var authorsList = new List<Author>()
{
new Author{ Firstname = "Bob", Lastname = "Smith", no = 2 },
new Author{ Firstname = "Fred", Lastname = "Jones", no = 3 },
new Author{ Firstname = "Brian", Lastname = "Brains", no = 4 },
new Author{ Firstname = "Billy", Lastname = "TheKid", no = 1 }
};
authorsList.RemoveAll(item => isEven(item.no));
foreach(var auth in authorsList)
{
Console.WriteLine(auth.Firstname + " " + auth.Lastname);
}
}
}
, ПРОИЗВОДИТ
Fred Jones
Billy TheKid
Я бы переназначил список из запроса LINQ, который отфильтровывал элементы, которые вы не хотели оставлять .
Использование ToArray () в общем списке позволяет вам удалить (элемент) в вашем общем списке:
List<String> strings = new List<string>() { "a", "b", "c", "d" };
foreach (string s in strings.ToArray())
{
if (s == "b")
strings.Remove(s);
}
Выберите элементы, которые вы делать нужно вместо того, чтобы пытаться удалить элементы, которые не нужны . Это намного проще (и, как правило, более эффективно), чем удаление элементов.
var newSequence = (from el in list
where el.Something || el.AnotherThing < 0
select el);
Я хотел опубликовать это как комментарий в ответ на комментарий, оставленный Майклом Диллоном ниже, но он слишком длинный и, вероятно, будет полезен в моем ответе:
Лично я бы никогда не удалял элементы один за другим. -one, если требуется удаление, вызовите RemoveAll
, который принимает предикат и только один раз переупорядочивает внутренний массив, тогда как Remove
выполняет операцию Array.Copy
. для каждого удаляемого вами элемента. RemoveAll
намного эффективнее.
И когда вы перебираете список в обратном направлении, у вас уже есть индекс элемента, который вы хотите удалить, поэтому было бы намного эффективнее вызвать RemoveAt
, потому что Remove
сначала выполняет обход списка, чтобы найти индекс элемента, который вы пытаетесь удалить, но вы уже знаете этот индекс.
В общем, я не вижу причин для вызова Remove
в цикле for. И в идеале, если это вообще возможно, используйте приведенный выше код для потоковой передачи элементов из списка по мере необходимости, чтобы не создавать вторую структуру данных вообще.
RemoveAt
, потому что Remove
сначала выполняет обход списка, чтобы найти индекс элемента, который вы пытаетесь удалить, но вы уже знаете этот индекс.
В общем, я не вижу причин для вызова Remove
в цикле for. И в идеале, если это вообще возможно, используйте приведенный выше код для потоковой передачи элементов из списка по мере необходимости, чтобы не создавать вторую структуру данных вообще.
RemoveAt
, потому что Remove
сначала выполняет обход списка, чтобы найти индекс элемента, который вы пытаетесь удалить, но вы уже знаете этот индекс.
В общем, я не вижу причин для вызова Remove
в цикле for. И в идеале, если это вообще возможно, используйте приведенный выше код для потоковой передачи элементов из списка по мере необходимости, чтобы не создавать вторую структуру данных вообще.
Простое и понятное решение:
Используйте стандартный цикл for, выполняющий в обратном направлении в вашей коллекции и RemoveAt (i)
, чтобы удалить элементы .