Джава.Как я могу проверить, был ли элемент успешно добавлен в набор и отслеживание индексов с forEach? - PullRequest
0 голосов
/ 30 декабря 2018

Мне нужно найти не похожие строки в матрице и вернуть набор таких строк.

Считается, что строки похожи, если наборы чисел, встречающиеся в этих строках, совпадают.

Пример: origin:

1 2 2 4 4
4 2 1 4
3 2 4 1 5 8

ожидаемый результат:

1 2 2 4 4
3 2 4 1 5 8

Мои идеи:

Очистить дубликаты из каждой строки с помощью преобразования двумерного массива в List>

Создайте новый набор int [] и добавьте строку, затем, если строка была добавлена, это означает, что строка не похожа. Тогда номер записи строки.вернуть созданный новый набор строк исходной матрицы.Я знаю, что могу проверить, был ли элемент добавлен через логическое возвращаемое значение метода Add Set.Но у forEach есть проблема, которая не обеспечивает индекс.И я не могу использовать выражения внутри forEach.Что мне делать?

Мой код:

class NonSimilar {
    private int[][] matrix;
    private List<Set<Integer>> rows = new ArrayList<>();

    public NonSimilar (int[][] matrix) {
        this.matrix = matrix;
        for (int i = 0; i < matrix.length; i++) {
            rows.add(Arrays.stream(matrix[i]).boxed().collect(Collectors.toSet()));
        }
    }

    public Set<int[]> getNonSimilarRows() {
        Set<Set<Integer>> nonSimularRows = new HashSet<>();
        rows.forEach(item -> nonSimularRows.add(item));
        // Now I have to check successfully added rows numbers and construct new Set from Origin matrix
        return new HashSet<int[]>();
    }
}

ОК.Я заменил forEach на итерацию, и теперь все работает правильно.

  public Set<int[]> getNonSimilarRows() {
        Set<Set<Integer>> nonSimularRows = new HashSet<>();
        //rows.forEach(item -> nonSimularRows.add(item));
        int index = -1;
        ArrayList<Integer> indexes = new ArrayList<>();
        for (Set<Integer> item : rows) {
            index++;
            if (nonSimularRows.add(item)) {
                indexes.add(index);
            }
        }
        HashSet<int[]> newSet = new HashSet<int[]>();
        for (Integer item : indexes) {
            newSet.add(matrix[item]);
        }
        return newSet;
    }

В любом случае код выглядит очень некрасиво, и я хочу получить совет о том, как я могу реорганизовать код с помощью современных подходов, таких как forEach и Stream API.

Ответы [ 4 ]

0 голосов
/ 31 декабря 2018

Вот еще одно решение, которое поддерживает набор неупорядоченный , который отслеживает повторяющиеся строки, а также поддерживает порядок путем сохранения результатов в списке:

import java.util.Set;
import java.util.HashSet;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.stream.Collectors;

public class Test {

    private static final int[][] rows = new int[][] {
        { 1, 2, 2, 4, 4 },
        { 4, 2, 1, 4 },
        { 3, 2, 4, 1, 5, 8 }
    };

    private static Set<Set<Integer>> seenRows = new HashSet<>();
    private static List<int[]> uniqueRows = new ArrayList<>();

    public static void main(String[] args) {
        for (int[] row : rows) {
            Set<Integer> uniqueNumbers = Arrays.stream(row).boxed().collect(Collectors.toSet());
            if (!seenRows.contains(uniqueNumbers)) {
                uniqueRows.add(row);
                seenRows.add(uniqueNumbers);
            }
        }

        for (int[] row : uniqueRows) {
            System.out.println(Arrays.toString(row));
        }
    }
}

Вывод:

[1, 2, 2, 4, 4]
[3, 2, 4, 1, 5, 8]
0 голосов
/ 31 декабря 2018

С этим

Вы можете написать это так:

public class NonSimilarRowsTest {
  @Test
  public void test() {
    int[][] matrix = {{1, 2, 2, 4, 4}, {4, 2, 1, 4}, {3, 2, 4, 1, 5, 8}};
    int[][] expected = {{1, 2, 2, 4, 4}, {3, 2, 4, 1, 5, 8}};
    assertEquals(expected, nonSimilarRows(matrix));
  }

  int[][] nonSimilarRows(int[][] matrix) {
    Set<Set<Integer>> rows = new HashSet<>();
    int[][] result = new int[matrix.length][];
    int length = 0;

    for (int[] row : matrix) {
      if (rows.add(toSet(row))) {
        result[length++] = row;
      }
    }

    return Arrays.copyOf(result, length);
  }

  Set<Integer> toSet(int[] array) {
    return Arrays.stream(array).boxed().collect(Collectors.toSet());
  }
}
0 голосов
/ 31 декабря 2018

Вам нужно всего 2 строки кода, чтобы удалить все «похожие» строки:

Set<Set<Integer>> sets = new HashSet<>();

List<int[]> nonSimilar = Arrays.stream(matrix)
    .filter(row -> sets.add(Arrays.stream(row).boxed().collect(Collectors.toSet())))
    .collect(Collectors.toList());

Метод add() для Set возвращает true, если набор был изменен - ​​т.е. если элементдобавляемого еще нет в наборе, поэтому мы можем использовать его в качестве фильтра.

List выбрано в качестве вывода потока для сохранения порядка (требование, которое, как представляется, подразумевается в данных примера).

Я предоставляю читателю возможность преобразовать List<int[]> в любой требуемый вывод, потому что это неважно для вопроса / ответа.


Некоторые тестовые коды:

int[][] matrix = {{1, 2, 2, 4, 4},{4, 2, 1, 4}, {3, 2, 4, 1, 5, 8}};
Set<Set<Integer>> sets = new HashSet<>();

List<int[]> nonSimilar = Arrays.stream(matrix)
    .filter(row -> sets.add(Arrays.stream(row).boxed().collect(Collectors.toSet())))
    .collect(Collectors.toList());

nonSimilar.stream().map(Arrays::toString).forEach(System.out::println);

Вывод:

[1, 2, 2, 4, 4]
[3, 2, 4, 1, 5, 8]

См. живая демонстрация .

0 голосов
/ 30 декабря 2018

Скажем так, что вам нужно дать первые неповторяющиеся строки существующей матрицы.Тогда вместо того, чтобы хранить индексы в отдельном списке, вы можете использовать Map, для которого уникальный ключ - это набор чисел в строке, а значение - сама строка.Вот полный класс с методом main для его проверки:

public class NonSimilar {
    private final int[][] matrix;

    public NonSimilar(int[][] matrix) {
        this.matrix = matrix;
    }

    public Set<int[]> getNonSimilarRows() {
        Map<Set<Integer>, int[]> map = new HashMap<>();
        for (int[] row : matrix) {
            map.putIfAbsent(convertRowToSet(row), row);
        }
        return new HashSet<>(map.values());
    }

    public Set<Integer> convertRowToSet(int[] row){
        return Arrays.stream(row).boxed().collect(Collectors.toSet());
    }

    public static void main(String[] args) {
        int[][] matrix = {{1, 2, 2, 4, 4}, {4, 2, 1, 4}, {3, 2, 4, 1, 5, 8}};
        Set<int[]> result = new NonSimilar(matrix).getNonSimilarRows();

        result.forEach(row -> System.out.println(Arrays.toString(row)));
    }
}

Теперь вы можете сказать, что он печатает

3 2 4 1 5 8
1 2 2 4 4

вместо

1 2 2 4 4
3 2 4 1 5 8

Это потому, что результатом является Set, а в наборе отсутствует концепция порядка.Если вы действительно хотите, чтобы он печатался в правильном порядке, вы можете использовать LinkedHashMap и вернуть LinkedHashSet.


ПРИМЕЧАНИЕ : вы можете даже сделать его корочеCollectors.toMap:

public Set<int[]> getNonSimilarRows() {
    Map<Set<Integer>, int[]> map = Arrays.stream(matrix)
            .collect(Collectors.toMap(this::convertRowToSet, Function.identity(), (r1, r2) -> null));
    return new HashSet<>(map.values());
}

(r1, r2) -> r1 означает, что вы принимаете дубликаты ключей и что вы должны сохранить первое найденное значение.Если вы хотите сохранить последнее найденное значение, вы можете заменить его на (r1, r2) -> r2.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...