✅ how do i join two lists?
i have 4 lists i want to join together. the plus operator doesnt work for this, even when converting to arrays.
22 Replies
u can use the "Addrange" method
List<int> list1 = new List<int> { 1, 2, 3 };
List<int> list2 = new List<int> { 4, 5, 6 };
List<int> list3 = new List<int> { 7, 8, 9 };
List<int> list4 = new List<int> { 10, 11, 12 };
List<int> result = new List<int>();
result.AddRange(list1);
result.AddRange(list2);
result.AddRange(list3);
result.AddRange(list4);
like this
or .Concat
Or using collection expression
var total = list1.Concat(list2).Concat(list3).ToList();
whats that
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/collection-expressions
For your use case you'd do
im making a chess engine and someone said this was really expensive
:ConfusedAnime:
Expensive in what sense?
Yes this would allocate a new List, so if you want minimal allocation you might want something else, but any time you're creating a new
List
you have to allocateno idea in what sense. i picked this language up like a week ago and learnt the basics in 2 days so i have no idea about whats better than what :shrug:
Hmm, can you show the code where you'd need to join the lists?
here are the structs too
done everything :thumbsup:
public static List<Move> GenerateWhitePawnMoves(ulong occupancy, ulong pawnBitboard)
{
PawnMoves pawnMoves = GetWhitePawnMoves(occupancy, pawnBitboard);
List<Move> left_attacks = GenerateMovesWithOffset(pawnMoves.LeftAttacks, 7);
List<Move> right_attacks = GenerateMovesWithOffset(pawnMoves.RightAttacks, 9);
List<Move> single_pushes = GenerateMovesWithOffset(pawnMoves.SinglePushForward, 8);
List<Move> double_pushes = GenerateMovesWithOffset(pawnMoves.DoublePushForward, 16);
// Create a new list and add all the other lists into it
List<Move> nextMoves = new List<Move>();
nextMoves.AddRange(left_attacks);
nextMoves.AddRange(right_attacks);
nextMoves.AddRange(single_pushes);
nextMoves.AddRange(double_pushes);
return nextMoves;
}
private static List<Move> GenerateMovesWithOffset(ulong bitboard, int offset)
{
List<Move> moves = new List<Move>();
while (bitboard != 0)
{
int src = BitScanForward(bitboard); // Find the index of the least significant bit set to 1
int dst = src + offset;
moves.Add(new Move { src = src, dst = dst });
bitboard &= bitboard - 1; // Clear the least significant bit
}
return moves;
}
private static int BitScanForward(ulong bitboard)
{
return (int)(Math.Log(bitboard & ~(bitboard - 1), 2));
}
cant read this without code blocks
ok,,i ll provide
You could use
AddRange
but it'll still allocate, if you want to reduce allocations, you might wanna use ArrayPoolDo you need it to be a list exactly?
if you just need to iterate it, there's a way to do this without allocations if you already have the other lists
i'd hope so
how do i do that?
how do i do that?
sorry for late response
You can allow a type to be for-looped over by means of structural typing. You have to wrap all the lists in a struct, have it implement
GetEnumerator
and the enumerator struct, which loops through all lists in order
you basically have to do an iterator state machine that loops through each list item-by-item
IEnumerable
is more convenient + it's lazily enumerated, but it does allocate memory for the iterators. If you implement these things manually with a struct, you don't need to heap allocate
IEnumerable
(linq / yield return) makes the state machine for youwhat would this look like in code?
look it up in the docs
Couple of things you can do to reduce allocations are
1. Rent an array from
ArrayPool
so something like ArrayPool<Move>.Shared.Rent(COUNT_GOES_HERE)
this will return an array Move[]
with at least COUNT_GOES_HERE
capactiy, after you're done using the you simply ArrayPool<Move>.Shared.Return(RENTED_ARRAY_GOES_HERE)
2. Make another version of GenerateMovesWithOffset
that takes in a Span<Move>
and writes the results to said span, although you need to make sure you have ways of informing the caller how many Moves
have been added to the span
Whether it's worth it to do any of these optimizations depends on how frequent GenerateWhitePawnMoves
and GenerateMovesWithOffset
get calledok got it. thank you :thumbsup: