Страницы

Поиск по вопросам

понедельник, 25 марта 2019 г.

В чём разница между «import java.util.*» и «import java.util.Scanner»

Вместо Scanner может быть что угодно - суть ясна. А именно: зачем использовать второй вариант, если первый и набирать короче, и пригодится когда понадобится что-то ещё из java.util? Изучаю Java и во многих примерах из книг и статьях в интернете используется второй вариант импорта, но нигде не видел объяснения почему именно так. Наверное, у него есть какие-то преимущества перед первым?


Ответ

Потому что в Java импорты нужны для разделения классов. Понятнее будет на примере. Допустим есть класс com.blabla.Scanner и вы написали import com.blabla.*;. А потом вам захотелось добавить импорт от java.util.Scanner и вы опять написали import java.util.*;. В этом случае, если вы в коде напишете Scanner, компилятор не поймет какой именно Scanner вам нужен. Полная запись импорта это не допустит
Помню, как-то добавил импорт от android.support.v7.widget.* и android.widget.*;. Когда я написал Toolbar IDE как раз и заругалась, так как он есть в обоих пакетах. Добавил к v7.widget.Toolbar и все.

Магия в Java Substring

Столкнулся со следующим непониманием, при переносе кода на c# под java. Нужно вытащить из строки символов подстроку, взять, начиная с некоторой k-й позиции n-символов. Собственно, код:
str = "((15+3)+14/2+(7*2)+3^2+(12+(7*2)))"; System.out.println(str.substring(27, 5));
Для меня, как человека немного знакомого с шарпом, код вполне понятный и логичный. В строке 33 символа, собственно, мне необходимо получить подстроку с 27 - символ ( по 32, символ ). Но в результате я получаю ошибку OutOfBoundException. Причем даже, если захочу взять с 10 позиции 3 символа. В чем может быть проблема?


Ответ

Согласно документации java, метод substring принимает 2 параметра: начальный индекс - откуда начинать вырезать, и конечный индекс - до куда вырезать.
substring(int beginIndex, int endIndex)

Как найти среднее (медиану) из трёх чисел?

Имеется три числа: 10, 20, 30. Как найти среднее из них (не самое большое и не самое маленькое), без множества условий?


Ответ

Отсортировать и взять среднее.
public static void main(String[] args) { int[] numbers = new int[] {31, 6, 13}; Arrays.sort(numbers); System.out.println(numbers[1]); }

Помогите упростить функцию

Помогите упростить функцию drawRect(int w, int h);. Понимаю, костыли за костылями, но на ошибках учатся. Мне важны какие то специальные методы для упрощения.
package com.company;
public class Main {
public static void drawRect(int w, int h) { for (int i = 0; i < w; i++) { if (i == 0) System.out.print("╔"); else if (i == (w - 1)) System.out.print("╗"); else System.out.print("═"); } System.out.print("
"); for (int i = 0; i < h; i++) {
if (i != h - 1) { System.out.print("║"); for (int j = 0; j < (w - 2); j++) { System.out.print(" "); } System.out.println("║"); } else { System.out.print("╚"); for (int j = 0; j < (w - 2); j++) { System.out.print("═"); } System.out.println("╝"); } } } public static void main(String[] args) { drawRect(30, 10); }
}
На выходе рисует
╔════════════════════════════╗ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ╚════════════════════════════╝


Ответ

В примитивном виде:
public static String stringRepeat(String str, int times) { return new String(new char[times]).replace("\0", str); }
public static void drawRect(int w, int h) { System.out.print("╔"); System.out.print(stringRepeat("=", w - 2)); System.out.println("╗");
for (int i = 0; i < h - 2; i++) { System.out.print("║"); System.out.print(stringRepeat(" ", w - 2 )); System.out.println("║"); }
System.out.print("╚"); System.out.print(stringRepeat("=", w - 2)); System.out.println("╝"); }
Далее вместо множества System.out можно загонять с помощью StringBuilder в отдельную переменную и в конце вывести

Для string.repeat можно использовать apache StringUtils

Как посчитать количество вхождений символа в строку?

Есть необходимость реализовать проверку на наличие нескольких запятых в строке. Т.е. можно использовать только одну запятую.
Но в целом достаточно узнать количество вхождений символа в строку. Остальное дописать не будет проблемой.
Какие есть способы это (посчитать количество вхождений символа) сделать?


Ответ

Регулярка Использовать StringUtils.countMatches из org.apache.commons.lang3.StringUtils
int occurrence = StringUtils.countMatches("a,b,c,d", ","); System.out.println(occurrence); Использовать string.split
String string = "a,b,c,d"; String []splitArray = string.split("\\,"); System.out.println("Запятых тут : " + (splitArray.length - 1) + " штук."); String testString = "a,b,c,d"; int occurrencesCount = testString.length() - testString.replace(",", "").length(); System.out.println(occurrencesCount); Java8
String testString = "a,b,c,d"; long occurrencesCount = testString.chars().filter(ch -> ch == ',').count(); System.out.println(occurrencesCount); Еще какой-нибудь способ

UPD нашел подобную тему на enSO: How do I count the number of occurrences of a char in a String?, несколько примеров оттуда:
Spring Framework
int spring = org.springframework.util.StringUtils.countOccurrencesOf(testString, ","); System.out.println("spring = " + spring); replaceAll
int replaceAll = testString.replaceAll("[^,]", "").length(); System.out.println("replaceAll = " + replaceAll); Java8
long java8 = testString.codePoints().filter(ch -> ch == ',').count(); System.out.println("java8 = " + java8); StringTokenizer
int stringTokenizer = new StringTokenizer(" " +testString + " ", ",").countTokens()-1; System.out.println("stringTokenizer = " + stringTokenizer);
Но в данном случае надо быть осторожным, так как, например, для строки a.b.c.d этот пример будет работать, а для строки a...b.c....d или ...a.b.c.d или a....b......c.....d... и т.д. — не будет. В итоге последовательность точек между каждой из букв посчитается лишь за один символ.

Как сделать метод пригодным для with?

Есть метод-обертка для загрузки YAML в объект.
def load_yaml(path): with io.open(path, encoding='utf-8') as fp: return yaml.safe_load(fp)
Хочу использовать with с этим методом:
with load_yaml('data.yml') as data: pass
Получаю ошибку:
... with load_yaml('data.yml) as data: AttributeError: __enter__
Что я делаю не так? Какие требования предъявляются к методу, чтобы его можно было использовать с with?


Ответ

Требования предъявляются не к "методу" (у вас, кстати, это не метод, а обычная функция), а к результату, который возвращает этот "метод".
После with вообще может стоять не только вызов функции, но и абсолютно любое выражение - сначала оно будет полностью вычислено, и уже над его результатом будет совершаться with. И вот как раз к этому результату есть определённые требования.
Для того, чтобы объект можно было использовать в with, у этого объекта должны быть определены специальные методы __enter__ и __exit__. Именно в этих методах вы и объясняете интерпретатору, как он должен открыть контекст работы с этим объектом и потом безопасно закрыть его.
Более подробно вы можете нагуглить по запросу "питон контекстный менеджер" или прочитать здесь:
https://habrahabr.ru/post/186608/#context
https://habrahabr.ru/post/196382/

Как удалить повторяющиеся элементы из двумерного списка?

list = [['03:30', 70.0], ['03:30', 135.0], ['03:30', 200.0], ['03:30', 280.0], ['04:00', 360.0], ['04:00', 430.0], ['04:30', 473.0], ['04:30', 573.0]]
Как удалить элементы с одинаковым временем и оставить с большим числом, чтобы получилось:
list = [['03:30', 280.0], ['04:00', 430.0], ['04:30', 573.0]]


Ответ

In [49]: from itertools import groupby
In [50]: res = [max(g) for _,g in groupby(lst, lambda x: x[0])]
In [51]: res Out[51]: [['03:30', 280.0], ['04:00', 430.0], ['04:30', 573.0]]
можно явно указать ключ для функции max()
In [53]: res = [max(g, key=lambda x: x[1]) for _,g in groupby(lst, lambda x: x[0])]
In [54]: res Out[54]: [['03:30', 280.0], ['04:00', 430.0], ['04:30', 573.0]]
Данный код группирует список списков по первому элементу:
In [57]: for k,g in groupby(lst, lambda x: x[0]): ...: print(k, list(g)) ...: 03:30 [['03:30', 70.0], ['03:30', 135.0], ['03:30', 200.0], ['03:30', 280.0]] 04:00 [['04:00', 360.0], ['04:00', 430.0]] 04:30 [['04:30', 473.0], ['04:30', 573.0]]
после этого мы выбираем в каждой группе элемент (список) с максимальным вторым элементом:
In [58]: for k,g in groupby(lst, lambda x: x[0]): ...: print(max(g, key=lambda x: x[1])) ...: ['03:30', 280.0] ['04:00', 430.0] ['04:30', 573.0]