Выделение каждых 2-х int из int [] и объединение их в массив uint64 [] с использованием выражения Lamda - PullRequest
1 голос
/ 03 октября 2019

Сторонний API, который я использую, возвращает массив типа int []. Давайте назовем его readWords согласно:

int[] readWords

Однако этот перенастроенный массив должен был быть uint []. Итак, я делаю следующее приведение:

Uint Ulongs = readWords(item => (ulong)item).ToArray();

Теперь проблема в том, что в некоторых случаях мне нужно объединить каждые 2 полученных слова int в Uint64 [].
Что было бы элегантноделать это с помощью лямбда-выражений?

Я думал об использовании чего-то в этом роде, но я не уверен, как:

Uint64[] longs = readWords
                 .Select(every 2 int into 1 Uint64)
                 .GroupBy(x => ...);

Обратите внимание, что каждые 2 дюйма должны быть объединены в Uint64 согласно:

Uint64 word0 = (readWords[0] & 0xFFFFFF) | ((Uint64)(readWords[1] & 0xFFFFFF) << 24);

Пример, если у нас есть:

int[] = new int[]{0x00123456, 0x00456789}

Полученное объединенное 64-битное слово должно быть:

0x0000456789123456

Ответы [ 2 ]

3 голосов
/ 03 октября 2019

Каждая комбинация из двух элементов представляет собой декартово соединение (readWords с само ):

int[] readWords = ...

var result = readWords
  .SelectMany(left => readWords
     .Select(right => /*TODO: put left and right combination here*/))
  .ToArray();

Для того, чтобысоздайте ulong из 2 int s, давайте использовать предоставленные вами битовые манипуляции:

(lelf, right) => unchecked(((ulong)left & 0xFFFFFF) | ((ulong)(right & 0xFFFFFF) << 24)))

Наконец

int[] readWords = ...

var result = readWords
  .SelectMany(left => readWords
     .Select(right => unchecked(((ulong)left & 0xFFFFFF) | 
                                ((ulong)(right & 0xFFFFFF) << 24))))
  .ToArray(); // materialization, if required

Давайте посмотрим:

  int[] readWords = new int[] { 1, 2, 3 };

  var result = readWords
    .SelectMany(left => readWords
      .Select(right => unchecked(((ulong)left & 0xFFFFFF) | 
                                 ((ulong)(right & 0xFFFFFF) << 24))))
    .ToArray();

  string report = string.Join(Environment.NewLine, 
    result.Select(item => item.ToString("x16")));

  Console.WriteLine(report); 

Результат:

0000000001000001
0000000002000001
0000000003000001
0000000001000002
0000000002000002
0000000003000002
0000000001000003
0000000002000003
0000000003000003

Редактировать: Та же идея ( Cartesian Join ), если вы хотите объединить, скажем,каждый четный элемент с каждым нечетным один:

  int[] readWords = new int[] { 0x00123456, 0x00456789 };

  var result = readWords
    .Where((value, index) => index % 2 == 0)    // even indexes only
    .SelectMany(left => readWords
      .Where((value, index) => index % 2 != 0)  // odd indexes only
      .Select(right => unchecked(((ulong)left & 0xFFFFFF) | 
                                 ((ulong)(right & 0xFFFFFF) << 24))))
    .ToArray();

  string report = string.Join(Environment.NewLine, 
    result.Select(item => item.ToString("x16")));

  Console.Write(report);

Результат:

  0000456789123456 

Редактировать2: Однако, Декартово объединение здесь, если вы хотите объединить

 item_0 and item_1,
 item_2 and item_3,
 item_4 and item_5,
...
item_2N and item_2N+1,
...

(см. Комментарии ниже; пожалуйста, обратите внимание, что мы не объединяем каждые предметов) просто Select:

var result = Enumerable
  .Range(0, readWords.Length / 2)
  .Select(index => new {
     left = readWords[2 * index],
     right = readWords[2 * index + 1]
   })
  .Select(pair => unchecked(((ulong)(pair.left) & 0xFFFFFF) | 
                            ((ulong)(pair.right & 0xFFFFFF) << 24)))
  .ToArray();
0 голосов
/ 03 октября 2019

Просто делать это в цикле без использования Linq - это нормально, поэтому я бы рекомендовал просто сделать это.

Однако, если вы хотите использовать Linq, вы можете написать вспомогательный метод, который преобразует IList<int> до IEnumerable<ulong> и используйте это с ToArray() у Линка следующим образом:

public static IEnumerable<ulong> Combine24BitIntsToUlongs(IList<int> ints)
{
    for (int i = 0; i < ints.Count / 2; ++i)
    {
        yield return (ulong)(ints[i*2] & 0xFFFFFF) | ((ulong)(ints[i*2+1] & 0xFFFFFF) << 24);
    }
}

Тогда:

int[] ints = {0x00123456, 0x00456789};

ulong[] ulongs = Combine24BitIntsToUlongs(ints).ToArray();

Console.WriteLine("{0:x}", ulongs[0]); // 456789123456
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...