Возможно, вы захотите использовать время, доказанное xPDF , и производные инструменты для извлечения текста вместо этого, поскольку pyPDF2, похоже, имеет различные проблемы с сохранением текста.
. Долгий ответ заключается в том, что существует множество вариантов того, как текст кодируется внутри PDF и что он может потребоваться для декодирования самой строки PDF, тогда может потребоваться сопоставить с CMAP, тогда может потребоваться проанализировать расстояние между словами и буквами и т. д.
В случае повреждения PDF-файла (т. е. отображения правильного текста, но при копировании он дает мусор), и вам действительно нужно извлечь текст, тогда вы можете захотеть преобразовать PDF в изображение (используя ImageMagik ), а затем используйте Tesseract , чтобы получить текст с изображения с помощью OCR.
Это зависит от того, как эффективный Вам нужны вещи быть. Просто итерация по списку, ища элемент, который удовлетворяет определенное условие, является O (n), но ArrayList - также. Содержит, если Вы могли бы реализовать, Равняется методу. Если Вы не делаете этого в циклах или внутренних циклах, этот подход, вероятно, очень хорошо.
при реальной необходимости в очень эффективных скоростях поиска по всей стоимости необходимо будет сделать две вещи:
, Конечно, создавая этот HashSet все еще имеет O (n) стоимость. Вы только собираетесь получить что-либо, если стоимость создания HashSet незначительна по сравнению с общей стоимостью всего содержания (), проверяет, что необходимо сделать. Попытка создать список без дубликатов является таким случаем.
<час> * () хэш-код Реализации () лучше всего сделан XOR'ing (^ оператор) хэш-коды тех же полей, которые Вы используете для, равняется реализации (но умножаются на 31 для сокращения шанса XOR получение 0)
Я сказал бы, что простое решение будет состоять в том, чтобы перенести объект и делегировать, содержит вызов к набору перенесенного класса. Это подобно компаратору, но не вынуждает Вас отсортировать получающийся набор, можно просто использовать ArrayList.contains ().
public class Widget {
private String name;
private String desc;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
public abstract class EqualsHashcodeEnforcer<T> {
protected T wrapped;
public T getWrappedObject() {
return wrapped;
}
@Override
public boolean equals(Object obj) {
return equalsDelegate(obj);
}
@Override
public int hashCode() {
return hashCodeDelegate();
}
protected abstract boolean equalsDelegate(Object obj);
protected abstract int hashCodeDelegate();
}
public class WrappedWidget extends EqualsHashcodeEnforcer<Widget> {
@Override
protected boolean equalsDelegate(Object obj) {
if (obj == null) {
return false;
}
if (obj == getWrappedObject()) {
return true;
}
if (obj.getClass() != getWrappedObject().getClass()) {
return false;
}
Widget rhs = (Widget) obj;
return new EqualsBuilder().append(getWrappedObject().getName(),
rhs.getName()).append(getWrappedObject().getDesc(),
rhs.getDesc()).isEquals();
}
@Override
protected int hashCodeDelegate() {
return new HashCodeBuilder(121, 991).append(
getWrappedObject().getName()).append(
getWrappedObject().getDesc()).toHashCode();
}
}
Существует три основных опции:
1), Если выполнение извлечения является главным и это практично, чтобы сделать так, использовать форму хеш-таблицы, созданной однажды (и измененный, когда Список изменяется).
2), Если Список удобно отсортирован или это практично для сортировки его, и O (зарегистрируйте n), извлечение достаточно, вид и поиск.
3), Если O (n) извлечение достаточно быстр или если это невозможно управлять/поддерживать структурой данных или альтернативой, выполните итерации по Списку.
Перед написанием кода, более сложным, чем простое повторение по Списку, стоит продумать некоторые вопросы.
, Почему что-то другое необходимо? (Время) производительность? Элегантность? Пригодность для обслуживания? Повторное использование? Все они являются хорошо причинами, независимо или вместе, но они влияют на решение.
, Сколько контроля Вы имеете над рассматриваемой структурой данных? Можно ли влиять, как это создается? Управляемый позже?
, Каков жизненный цикл структуры данных (и основные объекты)? Это создается внезапно и никогда не изменяется или очень динамичное? Ваш код может контролировать (или даже измениться), его жизненный цикл?
там другие важные ограничения, такие как объем потребляемой памяти? Информация о вопросе дубликатов? И т.д.
Если необходимо искать многих время в том же списке, он может окупиться для создания индекса.
Выполняют итерации однажды через и создают HashMap с, равняется значению, которое Вы ищете как ключ и соответствующий узел как значение. Если Вам нужно, все вместо любого из данного равняются значению, то позволенный карта иметь тип значения списка и создает целый список в начальном повторении.
Обратите внимание на то, что необходимо иметь размеры прежде, чем сделать это, поскольку издержки создания индекса могут омрачить просто пересечение, пока ожидаемый узел не найден.
Возможно, Список не то, в чем Вы нуждаетесь.
, Возможно, TreeSet был бы лучшим контейнером. Вы добираетесь, O (зарегистрируйте N), вставка и извлечение и заказанное повторение (но не позволит дубликаты).
LinkedHashMap мог бы быть еще лучше для Вашего варианта использования, проверить это также.
там какой-либо лучший путь, чем просто цикличное выполнение через и вручную сравнение этих двух полей для каждого объекта и затем повреждения при нахождении? Это просто кажется настолько грязным, ища лучший путь.
, Если Ваше беспокойство является пригодностью для обслуживания, Вы могли бы сделать то, что Fabian Steeg предлагает (это - то, что я сделал бы), хотя это, вероятно, не является "самым эффективным" (потому что необходимо отсортировать массив сначала и затем выполнить двоичный поиск), но конечно самый чистый и более оптимальный вариант.
, Если Вы действительно обеспокоены эффективностью, можно создать пользовательскую Реализацию списка, которая использует поле в объекте как хеш, и используйте HashMap в качестве устройства хранения данных. Но вероятно это было бы слишком много.
Затем необходимо изменить место, где Вы заполняете данные от ArrayList до YourCustomList.
Как:
List list = new ArrayList();
fillFromSoap( list );
К:
List list = new MyCustomSpecialList();
fillFromSoap( list );
реализация была бы чем-то как следующее:
class MyCustomSpecialList extends AbstractList {
private Map<Integer, YourObject> internalMap;
public boolean add( YourObject o ) {
internalMap.put( o.getThatFieldYouKnow(), o );
}
public boolean contains( YourObject o ) {
return internalMap.containsKey( o.getThatFieldYouKnow() );
}
}
В значительной степени как HashSet, проблемой здесь является HashSet, полагается на хорошую реализацию метода хэш-кода, который, вероятно, Вы не имеете. Вместо этого Вы используете в качестве хеша, "которому поле, которое Вы знаете", который является тем, который делает один объект, равняется другому.
, Конечно, реализация Списка от партии царапины, более хитрой, чем мой отрывок выше, вот почему, я говорю Fabian Steeg , предложение было бы лучше и легче реализовать (хотя что-то вроде этого будет более эффективным)
, Говорят нам, что Вы сделали в конце.
Создание HashMap этих объектов на основе значения поля как ключ могло стоить с точки зрения производительности, например, заполнить Карты однажды и найти объекты очень эффективно
Даже если бы равняется методу , были сравнение тех двух полей, то логически, это был бы просто тот же код как Вы делающий его вручную. Хорошо, это могло бы быть "грязно", но это - все еще корректный ответ
Если список , отсортировал , можно использовать двоичный поиск . В противном случае затем нет никакого лучшего пути.
при выполнении этого много это почти наверняка стоило бы Вашего, в то время как отсортировать список в первый раз. Так как Вы не можете изменить классы, необходимо было бы использовать Comparator
, чтобы сделать сортировку и поиск.
Учитывая Ваши ограничения, Вы застреваете с поиском грубой силы (или создание индекса, если поиск будет повторен). Можно ли разработать кого-либо о том, как эти ArrayList
сгенерирован - возможно, там существует некоторое пространство для маневра.
, Если все Вы ищете, более симпатичный код, рассмотрите использование Apache классы Наборов палаты общин, в особенности CollectionUtils.find () , для готового синтаксического сахара:
ArrayList haystack = // ...
final Object needleField1 = // ...
final Object needleField2 = // ...
Object found = CollectionUtils.find(haystack, new Predicate() {
public boolean evaluate(Object input) {
return needleField1.equals(input.field1) &&
needleField2.equals(input.field2);
}
});
Вы могли использовать Компаратор со встроенными методами Java для сортировки и двоичного поиска. Предположим, что у Вас есть класс как это, где a и b являются полями, Вы хотите использовать для сортировки:
class Thing { String a, b, c, d; }
Вы определили бы свой Компаратор:
Comparator<Thing> comparator = new Comparator<Thing>() {
public int compare(Thing o1, Thing o2) {
if (o1.a.equals(o2.a)) {
return o1.b.compareTo(o2.b);
}
return o1.a.compareTo(o2.a);
}
};
Затем сортируют Ваш список:
Collections.sort(list, comparator);
И наконец делают двоичный поиск:
int i = Collections.binarySearch(list, thingToFind, comparator);
Если Вы - пользователь моего ForEach DSL, он может быть сделан с Detect
запрос.
Foo foo = ...
Detect<Foo> query = Detect.from(list);
for (Detect<Foo> each: query)
each.yield = each.element.a == foo.a && each.element.b == foo.b;
return query.result();