Использование компаратора для наложения порядка в java (не сортировка!) [Duplicate]

Если вы не используете jQuery в своем коде, этот ответ для вас

Ваш код должен быть чем-то вроде этого:

function foo() {
    var httpRequest = new XMLHttpRequest();
    httpRequest.open('GET', "/echo/json");
    httpRequest.send();
    return httpRequest.responseText;
}

var result = foo(); // always ends up being 'undefined'

Феликс Клинг отлично справился с написанием ответа для людей, использующих jQuery для AJAX, я решил предоставить альтернативу для людей, которые этого не делают.

( Примечание. используя новый API fetch, угловые или обещания, я добавил еще один ответ ниже )


То, с чем вы столкнулись

Это краткое резюме «Объяснение проблемы» из другого ответа, если вы не уверены, прочитав это, прочитайте это.

A в AJAX означает асинхронность. Это означает, что отправка запроса (или, скорее, получение ответа) вынимается из обычного потока выполнения. В вашем примере .send немедленно возвращается, а следующий оператор return result; выполняется до того, как функция, которую вы передали, когда был вызван обратный вызов success.

Это означает когда вы возвращаетесь, слушатель, который вы определили, еще не выполнил, что означает, что возвращаемое вами значение не было определено.

Вот простая аналогия

function getFive(){ 
    var a;
    setTimeout(function(){
         a=5;
    },10);
    return a;
}

(Fiddle)

Возвращаемое значение a - undefined так как часть a=5 еще не выполнена. AJAX действует так, вы возвращаете значение до того, как сервер получил возможность сообщить вашему браузеру, что это за значение.

Одним из возможных решений этой проблемы является код повторно активно , сообщая вашей программе, что делать, когда расчет завершен.

function onComplete(a){ // When the code completes, do this
    alert(a);
}

function getFive(whenDone){ 
    var a;
    setTimeout(function(){
         a=5;
         whenDone(a);
    },10);
}

Это называется CPS . В основном, мы передаем getFive действие, которое необходимо выполнить, когда оно завершается, мы сообщаем нашему кодексу, как реагировать, когда событие завершается (например, наш вызов AJAX или в этом случае время ожидания).

Использование будет:

getFive(onComplete);

Который должен предупредить «5» на экране. (Fiddle) .

Возможные решения

Существуют два способа решения этой проблемы:

  1. Сделать AJAX синхронный вызов (позволяет называть его SJAX).
  2. Реструктурируйте свой код для правильной работы с обратными вызовами.

1. Синхронный AJAX - Не делайте этого !!

Что касается синхронного AJAX, не делайте этого! Ответ Феликса вызывает некоторые веские аргументы в пользу того, почему это плохая идея. Подводя итог, он заморозит браузер пользователя, пока сервер не вернет ответ и не создаст очень плохой пользовательский интерфейс. Вот еще краткое резюме из MDN о том, почему:

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

Короче говоря, синхронные запросы блокируют выполнение кода ... ... это может вызвать серьезные проблемы ...

Если вы имеете , вы можете передать флаг: Вот как это сделать:

var request = new XMLHttpRequest();
request.open('GET', 'yourURL', false);  // `false` makes the request synchronous
request.send(null);

if (request.status === 200) {// That's HTTP for 'ok'
  console.log(request.responseText);
}

2. Код реструктуризации

Пусть ваша функция принимает обратный вызов. В примере код foo может быть сделан для принятия обратного вызова. Мы сообщим нашему кодексу, как отреагировали , когда foo завершает работу.

Итак:

var result = foo();
// code that depends on `result` goes here

Становится:

foo(function(result) {
    // code that depends on `result`
});

Здесь мы передали анонимную функцию, но мы могли бы так же легко передать ссылку на существующую , чтобы он выглядел следующим образом:

function myHandler(result) {
    // code that depends on `result`
}
foo(myHandler);

Для получения дополнительной информации о том, как выполняется этот вид обратного вызова, проверьте ответ Felix.

Теперь давайте определим сам foo, чтобы действовать соответственно

function foo(callback) {
    var httpRequest = new XMLHttpRequest();
    httpRequest.onload = function(){ // when the request is loaded
       callback(httpRequest.responseText);// we're calling our method
    };
    httpRequest.open('GET', "/echo/json");
    httpRequest.send();
}

(скрипка)

Теперь мы сделали нашу функцию foo принять действие, которое будет выполняться, когда AJAX завершится успешно, мы можем продолжить это, проверив, не является ли статус ответа не 200 и действует соответственно (создайте обработчик сбоя и т. д.). Эффективное решение нашей проблемы.

Если вам все еще трудно понять это , прочитайте руководство по началу работы AJAX в MDN.

153
задан b4hand 14 May 2015 в 21:15
поделиться

18 ответов

Это происходит очень поздно, но в JDK есть класс только для того, чтобы иметь отсортированный список. Он назван (несколько не в порядке с другими интерфейсами Sorted*) "java.util.PriorityQueue". Он может сортировать либо Comparable<?> s, либо использовать Comparator.

Разница с List, отсортированная с использованием Collections.sort(...), заключается в том, что это будет поддерживать частичный порядок в любое время, с O (log (n)) с использованием структуры данных кучи, тогда как вставка в отсортированном ArrayList будет O (n) (т. е. с использованием двоичного поиска и перемещения).

Однако, в отличие от List, PriorityQueue не поддерживает индексированный доступ (get(5)), единственный способ получить доступ к элементам в куче - это вынуть их по одному (таким образом, имя PriorityQueue).

178
ответ дан Alice Purcell 26 August 2018 в 09:34
поделиться

То, что я сделал, это реализовать List с внутренним экземпляром со всеми делегированными методами.

 public class ContactList implements List<Contact>, Serializable {
    private static final long serialVersionUID = -1862666454644475565L;
    private final List<Contact> list;

public ContactList() {
    super();
    this.list = new ArrayList<Contact>();
}

public ContactList(List<Contact> list) {
    super();
    //copy and order list
    List<Contact>aux= new ArrayList(list);
    Collections.sort(aux);

    this.list = aux;
}

public void clear() {
    list.clear();
}

public boolean contains(Object object) {
    return list.contains(object);
}

После этого я внедрил новый метод «putOrdered», который вставляет правильную позицию, если элемент не существует или заменяется на всякий случай, если он существует.

public void putOrdered(Contact contact) {
    int index=Collections.binarySearch(this.list,contact);
    if(index<0){
        index= -(index+1);
        list.add(index, contact);
    }else{
        list.set(index, contact);
    }
}

Если вы хотите, чтобы повторяющиеся элементы просто реализовали addOrdered (или оба).

public void addOrdered(Contact contact) {
    int index=Collections.binarySearch(this.list,contact);
    if(index<0){
        index= -(index+1);
    }
    list.add(index, contact);
}

Если вы хотите избежать вложений, вы также можете исключить и исключить операцию неподдерживаемой операции в методах «добавить» и «установить».

public boolean add(Contact object) {
    throw new UnsupportedOperationException("Use putOrdered instead");
}

... а также вы должны быть осторожны с методами ListIterator, потому что они могут изменить ваш внутренний список. В этом случае вы можете вернуть копию внутреннего списка или снова выбросить исключение.

public ListIterator<Contact> listIterator() {
    return (new ArrayList<Contact>(list)).listIterator();
}
5
ответ дан Carlos Verdes 26 August 2018 в 09:34
поделиться

Вы хотите реализовать SortedSet , а именно TreeSet .

10
ответ дан cletus 26 August 2018 в 09:34
поделиться

Использовать TreeMultiset Google Guava. Guava - впечатляющий набор API.

Guava: https://github.com/google/guava

TreeMultiset: https: // google.github.io/guava/releases/snapshot/api/docs/com/google/common/collect/TreeMultiset.html

Одна проблема с предоставлением реализации списка, который поддерживает отсортированный порядок это обещание, сделанное в Javadocs метода 'add'.

28
ответ дан facundofarias 26 August 2018 в 09:34
поделиться

Использование LambdaJ

Вы можете попробовать решить эти задачи с помощью LambdaJ, если вы используете предыдущие версии для java 8. Вы можете найти его здесь: http://code.google.com/p / lambdaj /

Здесь у вас есть пример:

Сортировать Iterative

List<Person> sortedByAgePersons = new ArrayList<Person>(persons);
Collections.sort(sortedByAgePersons, new Comparator<Person>() {
        public int compare(Person p1, Person p2) {
           return Integer.valueOf(p1.getAge()).compareTo(p2.getAge());
        }
}); 

Сортировать по LambdaJ

List<Person> sortedByAgePersons = sort(persons, on(Person.class).getAge()); 

Конечно, такая красота влияет на производительность (в среднем 2 раза), но вы можете найти более читаемый код?

Сортировка с java 8 с использованием лямбда-выражения

Collections.sort(persons, (p1, p2) -> p1.getAge().compareTo(p2.getAge()));
//or
persons.sort((p1, p2) -> p1.getAge().compareTo(p2.getAge()));
4
ответ дан Federico Piazza 26 August 2018 в 09:34
поделиться

TreeSet не работает, потому что они не позволяют дублировать, и они не предоставляют метод для извлечения элемента в определенной позиции. PriorityQueue не будет работать, потому что он не позволяет получать элементы в определенной позиции, что является основным требованием для списка. Я думаю, вам нужно реализовать собственный алгоритм для поддержки отсортированного списка в Java с временем вставки O (logn), если вам не нужны дубликаты. Возможно, решение может использовать TreeMap, где ключ является подклассом элемента, переопределяющим метод equals, так что дубликаты разрешены.

4
ответ дан Giuseppe 26 August 2018 в 09:34
поделиться

Если вы хотите просто отсортировать список, используйте любой List и используйте Collections.sort () . Если вы хотите убедиться, что элементы в списке уникальны и всегда отсортированы, используйте SortedSet .

9
ответ дан Guillaume 26 August 2018 в 09:34
поделиться

Используйте метод sort () для сортировки списка, как показано ниже:

List list = new ArrayList();

//add elements to the list

Comparator comparator = new SomeComparator();

Collections.sort(list, comparator);

Для справки см. ссылку: http://tutorials.jenkov.com/java-collections/sorting. HTML

0
ответ дан HebeleHododo 26 August 2018 в 09:34
поделиться

Что вы хотите, это двоичное дерево поиска. Он поддерживает упорядоченный порядок, предлагая логарифмический доступ для поиска, удаления и вставки (если у вас нет вырожденного дерева, а затем оно линейно). Это довольно просто реализовать, и вы даже можете заставить его реализовать интерфейс List, но тогда индексный доступ становится сложным.

Второй подход заключается в том, чтобы иметь ArrayList, а затем реализацию сорта пузырьков. Поскольку вы вставляете или удаляете один элемент за раз, время доступа для вставок и абзацев является линейным. Поиски являются логарифмическими и постоянными доступа к индексу (времена могут быть разными для LinkedList). Единственный код, который вам нужен, - 5, может быть, 6 строк пузырьковой сортировки.

1
ответ дан Jakub Zaverka 26 August 2018 в 09:34
поделиться

Есть несколько вариантов. Я бы предложил TreeSet, если вы не хотите, чтобы дубликаты и объекты, которые вы вставляете, сопоставимы.

Вы также можете использовать статические методы класса Collections.

См. Коллекции # sort (java.util.List) и TreeSet для получения дополнительной информации.

12
ответ дан Janus Troelsen 26 August 2018 в 09:34
поделиться

Проблема с PriorityQueue заключается в том, что она подкрепляется простым массивом, а логика, которая получает упорядоченные элементы, выполняется «queue [2 * n + 1] и queue [2 * (n + 1)] "thingie. Он отлично работает, если вы просто тянете с головы, но делает его бесполезным, если вы пытаетесь в какой-то момент называть .toArray.

Я обойду эту проблему, используя com.google.common.collect.TreeMultimap, но я поставляю собственный Компаратор для значений, завернутых в Ordering, который никогда не возвращает 0.

ех. для Double:

private static final Ordering<Double> NoEqualOrder = Ordering.from(new Comparator<Double>() {

    @Override
    public int compare(Double d1, Double d2)
    {
        if (d1 < d2) {
            return -1;
        }
        else {
            return 1;
        }
    }
});

Таким образом, я получаю значения в порядке, когда я вызываю .toArray (), а также имеет дубликаты.

2
ответ дан Martin Klosi 26 August 2018 в 09:34
поделиться

Используйте TreeSet, который дает элементы в отсортированном порядке. ИЛИ используйте Collection.sort() для внешней сортировки с Comparator().

0
ответ дан Matteo Baldi 26 August 2018 в 09:34
поделиться

TreeMap и TreeSet предоставят вам итерацию по содержимому в отсортированном порядке. Или вы можете использовать ArrayList и использовать Collections.sort () для его сортировки. Все эти классы находятся в java.util

51
ответ дан Michael Borgwardt 26 August 2018 в 09:34
поделиться

Если вы хотите сохранить отсортированный список, который вы часто будете изменять (т. е. структуру, которая, помимо сортировки, позволяет дублировать и чьи элементы можно эффективно ссылать на индекс), затем используйте ArrayList, но когда вам нужно вставьте элемент, всегда используйте Collections.binarySearch (), чтобы определить индекс, в который вы добавляете данный элемент. Последний метод сообщает вам индекс, который вам нужно вставить, чтобы сохранить список в отсортированном порядке.

33
ответ дан Neil Coffey 26 August 2018 в 09:34
поделиться
import java.util.TreeSet;

public class Ass3 {
    TreeSet<String>str=new TreeSet<String>();
    str.add("dog");
    str.add("doonkey");
    str.add("rat");
    str.add("rabbit");
    str.add("elephant");
    System.out.println(str);    
}
0
ответ дан thinhvo0108 26 August 2018 в 09:34
поделиться

Вы можете использовать Arraylist и Treemap, так как вы сказали, что хотите повторять значения, но тогда вы не можете использовать TreeSet, хотя он также отсортирован, но вы должны определить компаратор.

1
ответ дан user 26 August 2018 в 09:34
поделиться

с Java 8 Comparator, если мы хотим отсортировать список, то вот 10 самых населенных городов в мире, и мы хотим отсортировать их по названию, как сообщает Time. Осака, Япония. ... Мехико, Мексика. ... Пекин, Китай. ... Сан-Паулу, Бразилия. ... Мумбаи, Индия. ... Шанхай, Китай. ... Дели, Индия. ... Токио, Япония.

 import java.util.Arrays;
 import java.util.Comparator;
 import java.util.List;

public class SortCityList {

    /*
     * Here are the 10 most populated cities in the world and we want to sort it by
     * name, as reported by Time. Osaka, Japan. ... Mexico City, Mexico. ...
     * Beijing, China. ... São Paulo, Brazil. ... Mumbai, India. ... Shanghai,
     * China. ... Delhi, India. ... Tokyo, Japan.
     */
    public static void main(String[] args) {
        List<String> cities = Arrays.asList("Osaka", "Mexico City", "São Paulo", "Mumbai", "Shanghai", "Delhi",
                "Tokyo");
        System.out.println("Before Sorting List is:-");
        System.out.println(cities);
        System.out.println("--------------------------------");

        System.out.println("After Use of List sort(String.CASE_INSENSITIVE_ORDER) & Sorting List is:-");
        cities.sort(String.CASE_INSENSITIVE_ORDER);
        System.out.println(cities);
        System.out.println("--------------------------------");
        System.out.println("After Use of List sort(Comparator.naturalOrder()) & Sorting List is:-");
        cities.sort(Comparator.naturalOrder());
        System.out.println(cities);

    }

}
0
ответ дан vipul gulhane 26 August 2018 в 09:34
поделиться

Самый эффективный способ реализовать отсортированный список, как вы хотите, - это реализовать индексируемый скипист, как здесь: Wikipedia: Indexable skiplist . Это позволило бы иметь вставки / удаления в O (log (n)) и позволяло бы иметь индексированный доступ в одно и то же время. И это также позволило бы дублировать.

Skiplist - довольно интересная и, я бы сказал, недооцененная структура данных. К сожалению, в библиотеке баз данных Java нет реализации skiplist, но вы можете использовать одну из реализаций с открытым исходным кодом или реализовать ее самостоятельно.

4
ответ дан vladich 26 August 2018 в 09:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: