Страницы

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

вторник, 28 января 2020 г.

Как работает деструктурирующее присваивание?

#javascript


Объясните как работает алгоритм деструктурирующего присваивания. Я решил проверить
поведение, но не могу понять, почему консоль выдает именно такие результаты.

Прежде чем задавать вопрос, я ознакомлялся со всеми источниками, кроме самой спецификации,
ибо она сложная для восприятия, и я не знаю английский.

Источники: ES6: Реструктуризующее присваивание, Деструктуризация, Деструктурирующее
присваивание.

1



var {a,aa,...aaa} = [2, 4, 23];

console.log(a, aa, aaa);




2



var [a,aa,...aaa] = {a:2, aa: 4, aaa: 23};

console.log(a, aa, aaa);




UPD: Воспользовался Babel.js, может он как - то поможет.
    


Ответы

Ответ 1



var {a,aa,...aaa} = [2, 4, 23]; var src = [2, 4, 23]; var a, aa, aaa; a = src.a; aa = src.aa; aaa = {}; for (var key in src) if (key !== 'a' && key !== 'aa' && src.hasOwnProperty(key)) aaa[key] = src[key]; console.log(a, aa, aaa); В таком поведении можно убедиться следующим образом: var {a, b, ...rest} = { __proto__: { b: 2, // декомпозиция в переменную d: 4 // исчезает, т. е. НЕ попадает в rest }, a: 1, // декомпозиция в переменную c: 3 // попадает в rest } console.log(a, b, rest) Если хочется потрошить массив как объект, то можно использовать декомпозицию с переименованием - ведь числа не могут быть иментами переменных, но обращаю внимание, что в aaa всё равно объект, а не массив: var { 0:a, 1:aa, ...aaa } = [2, 4, 23]; console.log(a, aa, aaa); var [a,aa,...aaa] = {a:2, aa: 4, aaa: 23}; var src = {a:2, aa: 4, aaa: 23}; var a, aa, aaa; var i = 0; aaa = []; for (var x of src) { // Упадёт прямо на of switch (i++) { case 0: a = x; break; case 1: aa = x; break; default: aaa.push(x); } } console.log(a, aa, aaa); Через [] можно деструктуризировать только итерируемые объекты: var src = { *[Symbol.iterator]() { yield 2; yield 4; yield 23; } }; var a, aa, aaa; var i = 0; aaa = []; for (var x of src) { switch (i++) { case 0: a = x; break; case 1: aa = x; break; default: aaa.push(x); } } console.log(a, aa, aaa); PS: А вообще лучше всё делать по-человечески: var [a, aa, ...aaa] = [2, 4, 23]; console.log(a, aa, aaa); var {a, aa, ...aaa} = {a:2, aa: 4, aaa: 23}; console.log(a, aa, aaa);

Ответ 2



В обоих случаях поведение непонятное так как вы объект пытаетесь пропихнуть в массив и наоборот. В документации смотрим синтаксис: var a, b, rest; [a, b] = [1, 2]; console.log(a); // 1 console.log(b); // 2 [a, b, ...rest] = [1, 2, 3, 4, 5]; console.log(a); // 1 console.log(b); // 2 console.log(rest); // [3, 4, 5] ({a, b} = {a:1, b:2}); console.log(a); // 1 console.log(b); // 2 ({a, b, ...rest} = {a:1, b:2, c:3, d:4}); Тут нету варианта деструктуризации массива в объект и наоборот. Справа и слева во всех примерах одинаковые скобочки, то есть массив деструктурируется в массив, а объект в объект. Вот конструкция которая работает как и предполагается, обратите снимание на скобочки: var [a,aa,...aaa] = [2, 4, 23, 144]; console.log(a, aa, aaa); Пункт 1. Запускаем babel и получаем код: var _ref = [2, 4, 23], a = _ref.a, aa = _ref.aa, aaa = _objectWithoutProperties(_ref, ["a", "aa"]); В a мы кладём ref.a так как _ref это массив то ref.a не задан. Тоже самое с aa. Теперь смотрим aaa,в него мы кладём все значения кроме a и aa, но так как a и aa не заданы, то на выходе получаем все три значения. Подводим итог, в a и aa ничего не кладётся, так как справа у массива нету переменной с названием a и aa, а в aaa мы кладём всё что осталось.

Ответ 3



Я, прочитав даже одну статью на MDN, понял суть. Для массивов: Не важно, как был получен массив(многих запутают переменни и функции в примерах на MDN), вся суть в то, что присваивание происходит в том же порядке, что переменные в первом массиве: var [a, b, c]=[vl1,vl2,vl3] a->vl1 b->vl2 c->vl3 Если в правом массиве больше значений, чем в левом, то лишние просто не используются, либо помещаются в переменную с оператором spread (...) var [a, b, c, ...d]=[vl1,vl2,vl3,vl4,vl5] a->vl1 b->vl2 c->vl3 d->[vl4,vl5] Для объектов: Практически тоже самое, только значение помещается в переменные по ключам свойств: var {a,c,b}={a:1,b:2,c:3} a->1 b->2 c->3 var {a,c,b,...w}={a:1,b:2,c:3,d:10,e:12} a->1 b->2 c->3 w->{d:10,e:12} В обоих случаях лишние переменные в левом массиве будут объявлены со значением undefined

Handler handler = new Handler() Ошибка: Handler is abstract; cannot be instantiated. Почему Android Studio импортирует не тот класс при автоимпорте?

#android #android_studio


Воздействуя Alt+Enter на слово Handler Андроид-Студио вставило автоматом строку: 

import java.util.logging.Handler;

    


Ответы

Ответ 1



Поскольку вопрос касается больше проблем с автоимпортом, попробую прояснить ситуацию. При следующих настройках автоимпорта (Editor-> General -> Auto Import): Все галочки в секциях XML и Java установлены Insert imports on paste -> All (влияет на импорт при копипасте кода) Мы получим следующие настройки автоимпорта: Если импортируемый класс один (как, например, Button) во всех доступных для импорта API, то он будет автоматически импортирован без лишних вопросов. Если классов для импорта более одного (как класс Handler), то требуется нажать Alt + Enter на таком классе и будет предложен выбор в выпадающем меню, какой именно класс импортировать Если ни одного класса в коде не останется (будут удалены при редактировании кода), то и импорт этого класса будет удален автоматически На мой взгляд это самая оптимальная настройка автоимпорта, которая не беспокоит в очевидных случаях и не своевольничает, если есть варианты выбора Официальная документация по настройке автоимпорта

Ответ 2



Оказывается вместо строки: import java.util.logging.Handler; нужно вставлять: import android.os.Handler; Т.е. среда разработки импортирует не тот Handler. ) Поэтому и не работает, например: handler.postDelayed( ... ) и т.д. По Alt+Enter вставился импорт: import java.util.logging.Handler автоматом, без предоставления выбора!

как можно в python открывать, редактировать, и сохранять графические файлы?

#python #изображения


я знаю, что для работы с файлами в python используется функция open, но как с помощью
нее или без ее помощи прямо в программе редактировать файлы, например, с расширением .png
    


Ответы

Ответ 1



Как я понимаю, по-разному. Вот, к примеру, с использованием библиотеки PIL(python imaging library): # конвертируем картинку from PIL import Image, ImageDraw img = Image.open('pic.png') # открываем PNG img.save('pic.gif') # сохраняем как GIF # создаем картинку, пишем в неё текст и сохраняем from PIL import Image, ImageDraw text = "Abracadabra :)" # готовим текст color = (0, 100, 100) # создаем цвет img = Image.new('RGB', (100, 100), color) # создаем изображение imgDrawer = ImageDraw.Draw(img) imgDrawer.text((10, 20), text) # пишем на изображении наш текст img.save("pic.png") # сохраняем в PNG # проводим манипуляции с картинкой, получаем ее свойства from PIL import Image, ImageDraw img = Image.open('pic.png') #открываем изображение format = img.format #формат изображения size = img.size #размер изображения histogram = image.histogram() # получаем гистограмму Библиотека позволяет осуществлять массу манипуляций с графическими форматами. Рекомендую также её форк - Pillow: как минимум, интересна существенно возросшей скоростью (для нас еще тем, что подддерживает, в отличие от PIL, формат PNG с одного из наших приборов). Предупреждения: в версии Pillow 5.0 прекратилась поддержка питона 3.3! начиная с версии Pillow 5.3.0 наблюдается "странная" работа с многостраничными TIFF-файлами. Пока не разобрались, в чём же дело. Так что, если вы работаете с подобным форматом, рекомендую пока не пользовать версии 5.3.0 и выше (новое) В версии Pillow 6.0.0 прекратилась поддержка питона 3.4! Если зачем-то предпочитаете оставаться на 3.4, пользуйтесь версией 5.4.1 (новое) В версии Pillow 6.0.0 убран ряд функций, ранее объявленных устаревшими. Большинство из них реализовано в модуле ImageFilter.

Создание ascii-art при помощи рекурсии

#python #рекурсия


Необходимо написать рекурсивную функцию, которая выводит на экран ASCII-art трапецию
следующего вида, в зависимости от числа n. Пример приведен для n = 4.

Теперь суть вопроса: по какой логике должна работать подобная рекурсивная функция?
У меня была мысль печатать определенно кол-во пробелов и звездочек, и передавать измененный
аргумент дальше по рекурсии, но что должно являться условием выхода из рекурсии, и
какое кол-во пробелов ставить я не знаю. 

       * * 
     * * * * 
   * * * * * * 
 * * * * * * * * 

    


Ответы

Ответ 1



def draw(n, indent=0): if n == 0: return draw(n-1, indent+1) print("{}{}".format(' ' * 2 * indent, ' '.join('*' * 2 * n)))

Ответ 2



Если совсем примитивно, то у Вас трапеция состоит из двух равносторонних треугольников, стороны которых соответствуют n: >>> def f(n): ... e = 0 ... for i in range(n): ... e += 1 ... print(' '*(n-e) + ' * *'*e + ' '*(n-e)) ... >>> f(4) * * * * * * * * * * * * * * * * * * * *

Ответ 3



Попытка в хвостовую рекурсию: def draw(n, i=0): width = 2 * (i + n) stars_count = 2 * i + 2 indent = (width - stars_count) // 2 print(' ' * indent + ' *' * stars_count) if n <= 1: return draw(n - 1, i + 1)

Какой смысл инструкции base.OnFormClosing() в одноименном методе?

#c_sharp #winforms


В коде события, в одном из примеров, увидел следующее:

protected override void OnFormClosing(FormClosingEventArgs e)
{
    //Написан код, который сохраняет пользовательские данные
    //

    base.OnFormClosing(e); //Интересна именно эта строчка
}


Какой смысл несет последняя строка? Для чего она нужна и когда используется?
    


Ответы

Ответ 1



Смотрите, в чём смысл виртуальных методов вообще? Он в том, что вы полностью подменяете метод родительского класса на свой. И теперь ответственность за то, чтобы сделать всё правильно, лежит на вас. Но чаще всего это слишком большая ответственность: вы не знаете/не помните всех вещей, которые должен сделать метод. Или просто не хотите дублировать код родительского метода. В этом случае вы просто вызываете родительский метод через base, он делает всё, что требуется от данного кода, а вы добавляете свой код до, после или вокруг вызова base-метода. Таким образом вы можете гарантировать, что вы ничего не забыли сделать при подмене метода.

Ответ 2



Ключевое слово base используется для доступа к членам базового из производного класса. То есть после сохранения пользовательских данных вызывается функция из производного класса. Подобное нужно если в базовом классе есть какой то функционал который нужны вызвать до/(или как в данном случае)после выполнения функции из дочернего класса.

Почему присвоенная переменная “зависит” другой переменной

#python #python_3x


Вот код:

a = {"1": "2", "3":"4"}
b = a
print(a, b)
b['1'] = "5"
print(a, b)


Почему в конце выводит {"1": "5", "3":"4"} это значение перемененной а

{"1": "5", "3":"4"} а это значение переменной b. Так вот почему когда изменилось
значение переменной b то и изменилось значение переменной a?
Может это я не прав, может так должно быть. Но если я не ошибаюсь, то b это копия a.   
    


Ответы

Ответ 1



b = a заставляет имя b ссылаться на тот же объект что и a имя, то есть a is b. Один объект — два имени. b = a никогда не копирует. Чтобы создать новый словарь, с теми же ключами, значениями: b = dict(a) В этом случае b['a'] = '5' изменяет новый словарь, не трогая исходный словарь. В общем случае, контейнеры могут определять .copy() метод. b это поверхностная копия, то есть сами ключи и значения не копируются, к примеру, a['3'] is b['3']. Чтобы создать копию и вложенных объектов рекурсивно: import copy c = copy.deepcopy(a)

Ответ 2



Потому что, когда Вы пишете b = a, то не создаете новый словарь, а создаете новую ссылку на уже существующий словарь. a и b начинают указывать на один и тот же объект словаря.

Ответ 3



a = {"1": "2", "3":"4"} b = a # переменная b ссылается на тот же словарь a is b # True Чтобы b ссылался на другой объект можно сделать copy: a = {"1": "2", "3":"4"} b= b.copy() a is b # False или так a = {"1": "2", "3":"4"} b = {"1": "2", "3":"4"} a is b # False

Ответ 4



Обе переменные являются ссылками на один объект, так как словарь - изменяемый объект. Так же будет и со списками.

Библиотека Android In-App Billing v3 Library

#android #in_app_purchases


Реализовал в своем приложении отключение рекламы на базе библиотеки с GitHub: "anjlab/android-inapp-billing-v3".

public class HelpActivity extends Activity implements BillingProcessor.IBillingHandler{
    ScrollView scrollView;


    TextView mTextView;
    BillingProcessor bp;
    static final String Off_ADVERTISING = "off_advertising";
    String fileName = "data";
    boolean m_off_advertising = false;
    SharedPreferences sPref;



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_help);
        // Убираем панель уведомлений
        this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        scrollView = (ScrollView)findViewById(R.id.scrollView);


        try {
            readFileXML();
        } catch (IOException e) {
            e.printStackTrace();
        }
        mTextView = (TextView)findViewById(R.id.textView11);

//        String licenseKey = getResources().getString(R.string.license_key);
//        bp = new BillingProcessor(this, licenseKey, this);
        bp = new BillingProcessor(this, null, this);

        mTextView.setOnClickListener(new View.OnClickListener() {
            @SuppressLint("ShowToast")
            @Override
            public void onClick(View v) {
               // bp.purchase(HelpActivity.this, "off_advertising");
                bp.purchase(HelpActivity.this, "android.test.purch");
            }
        });
        if(m_off_advertising){
            //показываем рекламу
            mTextView.setText("не показываем рекламу");

        }
    }

    @Override
    public void onProductPurchased(@NonNull String productId, @Nullable TransactionDetails
details) {

        mTextView.setText("Реклама убрана");
        m_off_advertising = true;
        saveData();
    }

    @Override
    public void onPurchaseHistoryRestored() {

//        mTextView.setText("Реклама восстановлена");
//        m_off_advertising = true;
//        saveData();
    }

    @Override
    public void onBillingError(int errorCode, @Nullable Throwable error) {

    }

    @Override
    public void onBillingInitialized() {

    }
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (!bp.handleActivityResult(requestCode, resultCode, data)) {
            super.onActivityResult(requestCode, resultCode, data);
        }
    }

    @Override
    protected void onPause() {
        saveData();
        super.onPause();
    }

    @Override
    protected void onResume() {

        try {
            readFileXML();
        } catch (IOException e) {
            e.printStackTrace();
        }

        super.onResume();
    }

    @Override
    public void onDestroy() {
        saveData();
        if (bp != null) {
            bp.release();
        }
        super.onDestroy();
    }


    void readFileXML() throws IOException {
        this.sPref = getSharedPreferences(this.fileName, 0);
        this.m_off_advertising = this.sPref.getBoolean(Off_ADVERTISING, false);

    }


    void saveData() {
        //Log.d(TAG, "m_off_advertising save " + this.m_off_advertising);
        this.sPref = getSharedPreferences(this.fileName, 0);
        SharedPreferences.Editor ed = this.sPref.edit();
        ed.putBoolean(Off_ADVERTISING, this.m_off_advertising);
        ed.commit();
    }


}


Но есть 2 но:
Первое: 
После покупки, нужно ещё раз нажать на текст купить, чтобы покупка отобразилась.
Второе:
Метод восстановления срабатывает всегда, и выполняет всё что в нём написано, не проверяя
id продукта

 @Override
    public void onPurchaseHistoryRestored() {

//        mTextView.setText("Реклама восстановлена");
//        m_off_advertising = true;
//        saveData();
    }


Как можно сделать проверку при включении и восстановлении для определённого продукта? 
    


Ответы

Ответ 1



Как я у себя реализовал отключение рекламы в приложении с применением библиотеки Android In-App-Billing-v3 от AnjLab? файл build.gradle модуля /app dependencies { // Ваши всевозможные библиотеки // ... compile 'com.anjlab.android.iab.v3:library:1.0.44' // ... // Ваши всевозможные библиотеки compile fileTree(include: ['*.jar'], dir: 'libs') testCompile 'junit:junit:4.12' } следите за последней release версией библиотеки, если нет возможности заходить на GitHub страничку и выписывать номер версии оттуда, то можно сделать следующее: compile 'com.anjlab.android.iab.v3:library:+' данная строчка будет выделена Android Studio, ставим курсор слева от + Жмем Alt + Enter, выбираем Replace with specific version Идем дальше ... класс SettingsFrag Мое приложение работает по принципу "В одной Activity отображаю все Fragment'ы." package com.my_best_of_the_best_application_name.ui.fragment; // список **import**'ов ... public class SettingsFrag extends Fragment implements BillingProcessor.IBillingHandler { private boolean adsStatus; // храним текущий статус отображения рекламы private boolean initialize; // храним готовность к покупкам private BillingProcessor bp; // переменная нашего процессора private PreferencesManager prefManager; // класс, который работает с SharedPreferences. Я для себя решил вынести всю логику отдельно private Resources resources; // для работы с ресурсами. Раз получаем и постоянно обращаемся private ToggleButton tbAdsState; // кнопка @Override public void onAttach(Context context) { super.onAttach(context); this.mContext = context; bp = new BillingProcessor(context, InAppBillingResources.getRsaKey(), InAppBillingResources.getMerchantId(), this); // инициализируем `BillingProcessor`. В документации на `GitHub` сказано, что для защиты от липовых покупок через приложения типа `freedom` необходимо в конструктор `BillingProcessor`'а передать еще и свой `MERCHANT_ID`. Где его взять - внизу текущего ответа опишу шаги prefManager = new PreferencesManager(context); // класс, который работает с `SharedPreferences` adsStatus = prefManager.getAdsStatus(); // получаем из `SharedPreferences` сохраненное состояние рекламы (ВКЛ / ВЫКЛ) resources = context.getResources(); // получаем "доступ" к ресурсам } @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { // создаем `View` экрана настроек View settView = inflater.inflate(R.layout.frag_sett_screen, container, false); // инициализация других полей tbAdsState = (ToggleButton) settView.findViewById(R.id.tbAdsState); // инициализация других полей // вешаем слушателя нажатий по кнопке `ToggleButton` tbAdsState.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // `adsStatus` : getAdsStatus из класса `PreferencesManager` // true - enabled (ВКЛ) | false - disabled (ВЫКЛ) if (adsStatus && initialize) { bp.purchase(getActivity(), InAppBillingResources.getSKU_Disable_Ads()); } if (!adsStatus) { tbAdsState.setChecked(false); Toast.makeText(getActivity(), getActivity().getResources().getString(R.string.txt_ads_is_already_disabled), Toast.LENGTH_LONG).show(); } } }); return settView; } @Override public void onResume() { super.onResume(); tbAdsState.setChecked(prefManager.getAdsStatus()); } // диалог, который скажет пользователю, что после покупки необходимо перезагрузиться private void restartDialog() { AlertDialog.Builder builder; View alertLayout = View.inflate(mContext, R.layout.dialog_restart, null); builder = new AlertDialog.Builder(mContext, R.style.AppThemeDialogStyleDark); builder.setTitle(resources.getString(R.string.msg_notification_Title)); builder.setView(alertLayout); builder.setCancelable(false); builder.setPositiveButton(resources.getString(R.string.ans_restart), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { restartApp(); } }); builder.show(); } // перезагружаем приложение private void restartApp() { Intent rIntent = mContext.getPackageManager().getLaunchIntentForPackage(mContext.getPackageName()); if (rIntent != null) { rIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); mContext.startActivity(rIntent); } } // ... другие методы класса // [START billing part of class] @Override public void onProductPurchased(@NonNull String productId, TransactionDetails details) { // Called when requested PRODUCT ID was successfully purchased // Вызывается, когда запрашиваемый PRODUCT ID был успешно куплен if (bp.isPurchased(productId)) { prefManager.setAdsStatus(false); // 1. записываем в `SharedPreferences` состояние рекламы (ВЫКЛ / false) tbAdsState.setChecked(false); // 2. устанавливаем `TogglButton` в соответствующее состояние restartDialog(); // 3. перезагружаем приложение } else { tbAdsState.setChecked(true); // иначе, если не прошла покупка, оставляем состояние (ВКЛ / true) } } @Override public void onPurchaseHistoryRestored() { //Вызывается, когда история покупки была восстановлена, // и список всех принадлежащих идентификаторы продуктов был загружен из Google Play // случай #2 (см. ниже) } @Override public void onBillingError(int errorCode, Throwable error) { // Вызывается, когда появляется ошибка. См. константы класса // для получения более подробной информации } @Override public void onBillingInitialized() { // Вызывается, когда bp был инициализирован и он готов приобрести initialize = true; } // [END billing part of class] } класс InAppBillingResources public class InAppBillingResources { private static final String RSA_KEY = "GFGFD156GF1SDF1.... FDS156DS"; // Ваш `RSA` ключ из `Google Play Developer Console` private static final String MERCHANT_ID = "16..1511.5..82"; // Ваш `MERCHANT_ID` из `Google Play Developer Console` private static final String SKU_DISABLE_ADS = "disable_ads"; // Ваш `product_id`, создается в `Google Play Developer Console` public static String getRsaKey() { return RSA_KEY; } public static String getMerchantId() { return MERCHANT_ID; } public static String getSKU_Disable_Ads() { return SKU_DISABLE_ADS; } } класс PreferencesManager public class PreferencesManager { private static SharedPreferences mSPref; private SharedPreferences.Editor mSPEditor; private static final String APP_PREF = "app_pref"; // имя файла настроек Вашего приложения private static final String APP_ADS_STATUS = "adsStatus"; // статус рекламы public PreferencesManager(Context context) { mSPref = context.getSharedPreferences(APP_PREF, Context.MODE_PRIVATE); } public void setAdsStatus(boolean adsStatus) { // true - enabled | false - disabled mSPEditor = mSPref.edit(); mSPEditor.putBoolean(APP_ADS_STATUS, adsStatus); mSPEditor.apply(); } public boolean getAdsStatus() { return mSPref.getBoolean(APP_ADS_STATUS, true); } } Дополнительная полезная информация Где взять в Google Play Developer Console свой RSA ключ - Читать Google Справку Где взять в Google Play Developer Console свой MERCHANT_ID - Читать Google Справку Метод восстановления. Вы можете реализовать восстановление покупок на стартовом activity приложения. Код инициализации BillingProcessor такой же. Метод onPurchaseHistoryRestored ниже @Override public void onPurchaseHistoryRestored() { //Вызывается, когда история покупки была восстановлена, // и список всех принадлежащих идентификаторы продуктов был загружен из Google Play // так Вы сможете НУЖНУЮ покупку проверить for (String sku : bp.listOwnedProducts()) { MyAppLogs.show("Owned Managed Product: " + sku); boolean wasBouhtg = sku.equals(InAppBillingResources.getSKU_Disable_Ads()); if (wasBouhtg) { // true - куплено // пишем в `SharedPreferences`, что отключили рекламу } else { // false - не куплено // пишем в `SharedPreferences`, что нужно показывать рекламу } } } // Если где-то я что-то упустил, сообщите, пожалуйста, в комментарии к моему ответу

Падающие символы

#c_sharp #net


Требуется написать программу которая будет выводит цепочку падающих символов. Первый
снизу символ должен быть белый, второй зеленый, остальные темно-зеленые.
Проблема в том, что цепочку падающих символов вывел, а как смещать цепочку символов
вниз так и не понял. Если я правильно понял то, надо установить курсор в начало строки
и потом уже как-то смещать её вниз.

using System;
namespace Task1
{
    class Program
    {
        static void Main(string[] args)
        {
            Random rand = new Random();
            int lenghtStr = rand.Next(1, 11);
            char[] column = new char[lenghtStr];
            for (int i = 0; i < lenghtStr; i++)
            {
                column[i] = (char)rand.Next('A', 'Z');
            }
            for (int i = 0; i < lenghtStr; i++)
            {
                if (i == (lenghtStr - 1))
                {
                    Console.ForegroundColor = ConsoleColor.White;
                    Console.WriteLine(column[i]);
                }
                else if (i == (lenghtStr - 2))
                {
                    Console.ForegroundColor = ConsoleColor.Green;
                    Console.WriteLine(column[i]);
                }
                else
                {
                    Console.ForegroundColor = ConsoleColor.DarkGreen;
                    Console.WriteLine(column[i]);
                }
            }
            Console.SetCursorPosition(0, 0);
            Console.ReadKey();
        }
    }
}

    


Ответы

Ответ 1



Создадим такой класс Символа class Sign { //генератор будем использовать в этом классе и снаружи public static Random RandomGen = new Random(); /// /// Получение случайного знака /// /// private char GetSign() { int t = RandomGen.Next(10); if (t <= 2) return (char)('0' + RandomGen.Next(10)); else if (t <= 4) return (char)('a' + RandomGen.Next(27)); else if (t <= 6) return (char)('A' + RandomGen.Next(27)); else return (char)(RandomGen.Next(32, 255)); } /// /// Отображение случайного символа белого цвета /// /// позиция слева /// позиция от верха public void ShowWhiteSign(int left, int top) { Console.ForegroundColor = ConsoleColor.White; Console.SetCursorPosition(left, top); Console.Write(GetSign()); } /// /// Отображение случайного символа зеленого цвета /// /// позиция слева /// позиция от верха public void ShowGreenSign(int left, int top) { Console.ForegroundColor = ConsoleColor.Green; Console.SetCursorPosition(left, top); Console.Write(GetSign()); Console.ForegroundColor = ConsoleColor.White; } /// /// Отображение случайного символа темного зеленого цвета /// /// позиция слева /// позиция от верха public void ShowDarkGreenSign(int left, int top) { Console.ForegroundColor = ConsoleColor.DarkGreen; Console.SetCursorPosition(left, top); Console.Write(GetSign()); Console.ForegroundColor = ConsoleColor.White; } /// /// Отображение пробела в нужном месте /// /// позиция слева /// позиция от верха public void ShowSpaceSign(int left, int top) { Console.SetCursorPosition(left, top); Console.Write(' '); } } Класс Отображателя такой class SignsShower { private int _heightWindow; private int _widthWindow; private int[] _widthPosSimple; private int[] _widthPosAddition; private readonly Sign _sign = new Sign(); //ctor public SignsShower() : this((Console.WindowWidth - 1), Console.WindowHeight) { } /// /// Отображатель символов /// /// ширина консольного окна минус 1 /// высота консольного окна public SignsShower(int windowWidth, int windowHeight) { Initialization(windowWidth, windowHeight); } private void Initialization(int windowWidth, int windowHeight) { //получаем высоту окна _heightWindow = windowHeight; int h1 = _heightWindow / 2; //половина высоты int h2 = _heightWindow / 4; //четверть высоты //ширина окна _widthWindow = windowWidth; //два массива размером в ширину окна _widthPosSimple = new int[_widthWindow]; _widthPosAddition = new int[_widthWindow]; //заполнение массивов случайными числами for (int i = 0; i < _widthWindow; i++) { _widthPosSimple[i] = Sign.RandomGen.Next(_heightWindow); int k = (i % 11 != 10) ? 2 : 1; int min = h2 * k; int max = h1 * k; _widthPosAddition[i] = Sign.RandomGen.Next(min, max); } } /// /// Отображение символов в случайных позициях с необх.цветом /// public void SignShow() { for (int i = 0; i < _widthWindow; i++) { if (_widthPosSimple[i] < 10) { //отображение темного символа _sign.ShowDarkGreenSign(i, _widthPosSimple[i]); } else if (_widthPosSimple[i] < 25) { //отображение зеленого символа _sign.ShowGreenSign(i, _widthPosSimple[i]); } else { //отображаем белый символ _sign.ShowWhiteSign(i, _widthPosSimple[i]); } //сдвигаем координату по высоте для отображения в след. цикле вызова SignShow() _widthPosSimple[i] = CheckNextHeightPosition(_widthPosSimple[i] + 1, _heightWindow); //пробельный символ int next = _widthPosSimple[i] - _widthPosAddition[i]; int nextPos = CheckNextHeightPosition(next, _heightWindow); _sign.ShowSpaceSign(i, nextPos); } } /// /// Проверка значения след.позиции /// /// значение след.положения по высоте /// общая допустимая высота /// private int CheckNextHeightPosition(int next, int height) { next = next % height; if (next < 0) { return next + height; } else { return next; } } } Теперь включим в работу эти классы так static void Main(string[] args) { //отображатель SignsShower signsShower = new SignsShower(); //готовим консоль Console.Clear(); Console.CursorVisible = false; //в бесконечном цикле с вычисляемой задержкой отображаем int ms = 0; while (true) { //засекаем время DateTime timeMark = DateTime.Now; //отображаем символы signsShower.SignShow(); //задержка ms = 10 - (int)((TimeSpan)(DateTime.Now - timeMark)).TotalMilliseconds; if (ms > 0) System.Threading.Thread.Sleep(ms); } } Не знаю, правильно ли я вас понял, но по крайней мере у вас теперь есть от чего плясать.

Ответ 2



Конечно моё решение не такое красивое и лаконичное как у @Bulson, но думаю оно всё таки тоже имеет право на существование. Захотелось придумать что-то своё, извращённое так скажем;) using System; using System.Threading; namespace Task1 { class Program { static object locker = new object(); static int Generate(int a, int b) // Метод генерирования рандомных чисел { Random rand = new Random((int)DateTime.Now.Ticks & 0x0000FFFF); return rand.Next(a, b); } static void Matrix(object numberColumn) // метод вывода столбцов с символами, в качестве параметра принимает позицию строки курсора { while(true) { int lenghtColumn = 0; int position = 0; // Позиция столбца курсора const int maxLenght = 40; // максимальная длинна столбца Random rand = new Random(); int count = Generate(25, 39); //длинна столбца Thread.Sleep(555); for (int i = 0; i != maxLenght + count; i++) { lock (locker) { Console.ForegroundColor = ConsoleColor.Black; //Задаём чёрный цвет тексту for (int j = 0; j <= position; j++) // В цикле закрашиваем символы черным квадратом { Console.SetCursorPosition((int)numberColumn, j); // Устанавливаем позицию курсора Console.WriteLine("█"); // Так как мы поменяли цвет текста в консоли на чёрный, то квадрат не будет красным } if (lenghtColumn < count && position != 40) { ++lenghtColumn; } else if (position == maxLenght) { --lenghtColumn; } if (lenghtColumn >= 3) { for (int k = position - (lenghtColumn - 1); k <= position - 2; k++) { Console.SetCursorPosition((int)numberColumn, k); Console.ForegroundColor = ConsoleColor.DarkGreen; Console.WriteLine((char)rand.Next('A', 'z')); } } if (lenghtColumn >= 2) { Console.SetCursorPosition((int)numberColumn, position - 1); Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine((char)rand.Next('A', 'z')); } if (lenghtColumn >= 1) { Console.SetCursorPosition((int)numberColumn, position); Console.ForegroundColor = ConsoleColor.White; Console.WriteLine((char)rand.Next('A', 'z')); if (position != maxLenght) position++; } } } } } static void Main(string[] args) { Console.SetWindowSize(100, 42); Thread t; for (int i = 0; i < 100; i++) { t = new Thread(Matrix); t.Start(i); } Console.ReadKey(); } } }

Правильность импртов PyQt

#python #python_3x #pyqt5


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

1 вариант

import sys
from PyQt5.QtWidgets import *


class Io(QWidget):
    def __init__(self):
        super().__init__()
        b = QCommandLinkButton("Переход")
        layout = QVBoxLayout()
        layout.addWidget(b)
        self.setLayout(layout)
        self.show()


if __name__ == "__main__":
    app = QApplication(sys.argv)
    main = Io()
    sys.exit(app.exec_())




2 вариант

import sys
from PyQt5 import QtWidgets


class Io(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        b = QtWidgets.QCommandLinkButton("Переход")
        layout = QtWidgets.QVBoxLayout()
        layout.addWidget(b)
        self.setLayout(layout)
        self.show()


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    main = Io()
    sys.exit(app.exec_())




3 вариант

import sys
from PyQt5.QtWidgets import QWidget, QApplication, QVBoxLayout, QCommandLinkButton


class Io(QWidget):
    def __init__(self):
        super().__init__()
        b = QCommandLinkButton("Переход")
        layout = QVBoxLayout()
        layout.addWidget(b)
        self.setLayout(layout)
        self.show()


if __name__ == "__main__":
    app = QApplication(sys.argv)
    main = Io()
    sys.exit(app.exec_())

    


Ответы

Ответ 1



Есть замечательное правило, действующее во многих командах "Заимпортил звёздочку - получил по мордочке". А выбор между вторым и третьим вариантом - пожалуй, дело вкуса.

Ответ 2



Если вы хотите все qt имена в одном пространство имён импортировать, можно Qt использовать: from PyQt5 import Qt Это позволяет писать: Qt.QApplication, Qt.QPoint, Qt.QPainter, etc. Недостаток, что все qt модули импортируются, увеличивая время загрузки и потребляемую память, если фактически вам нужны только отдельные модули. Не используйте from module import * за исключением специальных случаев: в REPL или в __init__.py файле. Пример оправданного использования: asyncio/__init__.py—asyncio предоставляет "плоский" публичный интерфейс (имена доступны прямо как asyncio.name), не смотря на то что реализация распределена по многочисленным вложенным модулям. Можно ли отнести импорты pyqt к специальным случаям, зависит могут ли конфликтующие имена появиться сегодня и в будущем (если все имена в __all__ начинаются с Q*, то нет опасности, что вы их перепутаете со своими). Не применяйте правила вслепую, используйте голову PEP-8: "A Foolish Consistency is the Hobgoblin of Little Minds."

Почему не работает встроенный JavaScript? [закрыт]

#javascript #html #события


        
             
                
                    
                        
                            Закрыт. Этот вопрос не по теме. Ответы на него в данный
момент не принимаются.
                            
                        
                    
                
                            
                                
                
                        
                            
                        
                    
                        
                            Хотите улучшить этот вопрос? Переформулируйте вопрос,
чтобы он соответствовал тематике «Stack Overflow на русском».
                        
                        Закрыт 2 года назад.
                                                                                
           
                
        
Почему не работает этот код: 













    


Ответы

Ответ 1



img

Ответ 2



опечатка в свойстве нужно src а не scr

Как правильно написать “if else” в теле “for” без повторений

#html #алгоритм #frontend #code_style #velocity


Мой код ревьювер сказал, изменить текущий так как он не соответсвует принципу "Don't
repeat yourself" en.wikipedia.org/wiki/Don%27t_repeat_yourself
Конструкцию if else надо изменить. Технология ".vm", java apach velocity template,
но думаю это не очень важно. 

#set($first = "true")
#foreach($item in $data)
    #if($first == "true")
        
#set($first = "false") #else
#end

str1

str2

str3

##//Close div created in (if else) #end


Ответы

Ответ 1



Но, на мой взгляд, это типичный пример принесения читаемости кода в жертву догматическому следованию "принципу".

Ответ 2



Признак первого элемента при переборе можно получить из переменной $foreach: $foreach.first Следовательно код может принять вид: #foreach($item in $data)

str1

str2

str3

##//Close div created in (if else) #end

Ответ 3



Можно попробовать упростить до: #set($first = "first") #foreach($item in $data)
...
#if($first == "first") #set(first = "") #end #end не знаком с этим языком шаблонов, поправьте. Идея ясна должна быть

Изменение css стиля элемента при наведении на другой элемент с помощью JS

#javascript


Здравствуйте! Никак не получается решить проблему, знания JS очень скудные. Нужно
заставить квадраты двигаться при наведении на текст над ним.
Как заставить этот скрипт работать для всех элементов с одинаковым классом? Я пробовал
через querySelectorAll, но максимум чего удалось добиться - это одновременное движение
всех квадратов вниз, без обратного движения. Нужно, чтобы каждый работал по отдельности.
CSS не подойдёт, в оригинале блоки расположены далеко друг от друга.
Помогите пожалуйста, я уже всю голову себе сломал :(



var dms = document.querySelector('.dm-short-news');
var dmi = document.querySelector('.dm-intro-news');

dms.onmouseover = function(e) {
  dmi.style.transform = 'translateY(50px)';
};

dms.onmouseout = function(e) {
  dmi.style.transform = '';
};
.dm-intro-news {
  width: 200px;
  height: 200px;
  background: #333333;
  transition: 0.5s;
}
.wr {display: inline-block}
Текст
Текст
Текст


Ответы

Ответ 1



При этой верстке можно и без JS обойтись .dm-intro-news { width: 200px; height: 200px; background: #333333; transition: 0.5s; } .wr {display: inline-block;transition:2s} .dm-short-news{display:inline-block} .dm-short-news:hover~.dm-intro-news{margin-top:20px}
Текст
Текст
Текст


Ответ 2



Получилось решить проблему собственными силами. NodeList.prototype.forEach = Array.prototype.forEach; var dmns = document.querySelectorAll('.wr'); dmns.forEach(function(dmn) { dmn.querySelector('.dm-short-news').addEventListener('mouseenter', function() { dmn.querySelector('.dm-intro-news').style['transform'] = 'translateY(50px)'; }) dmn.querySelector('.dm-short-news').addEventListener('mouseout', function() { dmn.querySelector('.dm-intro-news').style['transform'] = 'translateY(0px)'; }) }); .dm-intro-news { width: 200px; height: 200px; background: #333333; transition: 0.5s; } .wr { display: inline-block }
Текст
Текст
Текст


Как перехватить исключение

#cpp #исключения #деструктор


Почему данный код не ловит исключение?

#include 

class A
{
private:

public:
    A()
    {
        std::cout << "A::A()" << std::endl;
    }
    ~A()
    {
        throw 1;
        std::cout << "A::~A(int)" << std::endl;
    }
};

int main()
{
    A* p = nullptr;

    try
    {
        p = new A();
        delete p;
    }
    catch(...)
    {
        std::cout << "catch(...)" << std::endl;
    }

    return 0;
}

    


Ответы

Ответ 1



Выбрасывать исключение из деструктора не рекомендуется и на это есть ряд причин. это может привести к утечкам памяти, невозможно обеспечить какие-либо гарантии безопасности, исключение из деструктора может вылететь во время раскрутки стека, что приведет к разным последствия в зависимости от объекта. Посмотрим на Ваш код. delete p; Как известно, сначала delete-expression вызывает деструктор и затем освобождает память. Если деструктор выбрасывает исключение, то до освобождения памяти дело уже не дойдет и это приведет к утечке. При реализации, например, контейнеров, невозможно обеспечить какие-либо гарантии относительно безопасности исключений. Например: vector.push_back();//Вектор был не пуст Допустим, произошло выделение памяти. Значит старые элементы копируются в новую область памяти. Если копирование прошло успешно, а при уничтожении старых объектов вылетело исключение, то мы получим часть неуничтоженных объектов и утечку памяти. Если же при копировании вылетело исключение и вектор попытается уничтожить уже сконструированные объекты, а при их уничтожении вылетит исключение, то получим ту же утечку, плюс дальше "полетит" уже другое исключение. Если исключение вылетает из деструктора автоматического объекта во время раскрутки стека, то, в соответствии со стандартом, это приводит к вызову std::terminate 15.2 Constructors and destructors The process of calling destructors for automatic objects constructed on the path from a try block to a throw-expression is called “stack unwinding.” [Note: If a destructor called during stack unwinding exits with an exception, terminate is called (15.5.1). So destructors should generally catch exceptions and not let them propagate out of the destructor. —end note] Это цитата из C++03, но в последующих стандартах поведение не поменялось. Начиная с C++11 все деструкторы по-умолчанию имеют спецификацию исключений noexcept. При нарушении этой спецификации вызывается std::terminate: Whenever an exception is thrown and the search for a handler (15.3) encounters the outermost block of a function with an exception-specification that does not allow the exception, then, — if the exception-specification is a dynamic-exception-specification, the function std::unexpected() is called (15.5.2), — otherwise, the function std::terminate() is called (15.5.1). То есть, начиная с C++11 любое исключение, покинувшее деструктор, приводит к вызову std::terminate и аварийному завершению программы, тем самым, как минимум, обеспечивая единое поведение и возможность предоставления каких-либо гарантий. Деструктору возможно указать другую спецификацию исключений: ~A() noexcept(false) { /*...*/ } Но при этом, если вылетит исключение, мы получим все проблемы указанные выше. Итого: исключение, покинувшее деструктор создает много проблем, и не дает никакой пользы, поэтому общая рекомендация - никогда не позволять исключениям покидать деструктор.

Ответ 2



Вообще-то в деструкторах генерировать исключения категорически не рекомендуется. Как я понимаю (на конкретное место в стандарте не укажу) - фактически деструкторы объявлены как noexcept - а значит, при генерации в них исключения будет вызван terminate. Вот, выполните этот код: #include #include class A { private: public: A() { std::cout << "A::A()" << std::endl; } ~A() { throw 1; std::cout << "A::~A(int)" << std::endl; } }; int main() { std::set_terminate([](){ std::cout << "terminate called\n"; exit(1);}); A* p = nullptr; try { p = new A(); delete p; } catch(...) { std::cout << "catch(...)" << std::endl; } return 0; } Как видите, вызывается terminate - как результат генерации исключения там, где его быть не должно. "По-моему, так" (с) Пух

Объясните логику работы выражения

#java #cpp #битовые_операции


Объясните пожалуйста, как работает это выражение !(a & (a - 1))
В плюсах совершенно не понимаю, в Java ! нельзя применять к int.

        private int isPow2(int a)
        {
          return !(a & (a - 1));
        }

    


Ответы

Ответ 1



Возьмем два числа A и B. Выражение A & B будет равно 0 только тогда, когда числа А и B не содержать единичных бит на одних и тех же позициях. Если (a & (a - 1) = 0, то a и a-1 не содержат общих единичных бит. Давайте возьмем число а и попробуем вычесть одну единицу. Когда мы отнимаем единицу, смотрим на младший бит. если он равен 1 то мы просто заменяем его на 0. Но если там стоит 0, то мы должны заимствовать из старшего бита. Мы заменяем каждый бит с 0 на 1 до тех пор, пока не найдем бит, равный 1. Затем вы инвертируем найденную единицу в ноль. То есть чтобы получить ноль при выполнении операции &, нам нужно, чтобы младшие нули в a соответствовали единицам в a - 1, а последний(и единственный) единичный бит в a(если существует) стал бы нулем в a - 1 - только таким образом во всех позициях будут отсутствовать единичные биты. Это условие выполняется только, если число является степенью двойки, например 1000 & 0111 = 0 10000 & 01111 = 0 число равно 0 0000 & 1111 = 0 Поэтому (a & (a - 1)) = 0, если а - степень двойки или ноль

Ответ 2



Операция a&(a-1) обнуляет крайний справа единичный бит или дает 0, если такового нет: a = 01011000 a-1 = 01010111 a&(a-1) = 01010000 Таким образом, для всех a, являющихся степенями двойки (у которых только один бит - единичный, остальные - нулевые) и 0, выражение дает 0, для чисел, таковыми не являющимися - ненулевое значение. ! инвертирует полученное логическое значение (0 - false, не нуль - true), так что ваша функция дает 1, если a - степень двойки или нуль, и нуль в противном случае.

typedef с рекурсией в си

#c #gcc #clang


Коллеги, подскажите pls, можно ли в компиляторах gcc, clang объявить содержащий рекурсию тип?

Например, без рекурсии чудесно проходит, а с ней - нет:

struct {
    int a;
    char *b;
    my_t *next;
} typedef my_t;


Заранее признателен за подсказку.
    


Ответы

Ответ 1



Либо typedef struct my_t { int a; char *b; struct my_t *next; } my_t; либо typedef struct my_t my_t; struct my_t { int a; char *b; my_t *next; // или `struct my_t *next;` }; либо struct my_t { int a; char *b; struct my_t *next; }; typedef struct my_t my_t; Ключевое слово typedef можно порекомендовать ставить первым в typedef-объявлении, а не запихивать его в середину. Другими словами проблема "рекурсивного определения" решается путем назначения struct-типу непустого тэга и использования полного имени типа struct при объявлении внутреннего указателя struct my_t { int a; char *b; struct my_t *next; }; а куда при этом вы поставите ваш typedef struct my_t my_t; (до объявления струкутры, после объявления струкутры, сольете в одно объявление или вообще не будете делать typedef) - это уже вопрос посторонний.

Ответ 2



struct myt; typedef struct myt my_t; struct myt { int a; char *b; my_t *next; };

&& и || с разными типами данных

#javascript


Я только начал изучать JavaScript и прорешивал задачки.  

И начали попадаться такие задания как:
•   Чему равно 2 && 1 && null && 0 && undefined ?
•   Чему равно 0 || "" || 2 || undefined || true || falsе ?  

Как можно сравнивать разные типы данных? 
    


Ответы

Ответ 1



&& и || это операции логического И и ИЛИ. На вход они принимают два логических операнда и возвращает результат логического типа В JavaScript нет строгой типизации, поэтому операнды преобразовываются к тому типу, который требуется в выражении. Т.е. в вашем случае все операнды преобразуются в логический тип. Алгоритм преобразования такой: Значение | Преобразуется в... -----------------|-------------------- undefined, null | false Числа | Все true, кроме 0, NaN -- false. Строки | Все true, кроме пустой строки "" -- false Объекты | Всегда true

Ответ 2



Если обратиться к спецификации: LogicalANDExpression : LogicalANDExpression && BitwiseORExpression 1. Пусть lref результат вычисления LogicalANDExpression. 2. Пусть lval будет результатом GetValue(lref). 3. Пусть lbool результат ToBoolean(lval). 4. Если lbool - false, вернуть lval. 5. Пусть rref это результат вычисления BitwiseORExpression. 6. Вернуть GetValue(rref). В случае && левый операнд приводится к bool и если значение false возвращается сам операнд. В противном случае возвращается правый операнд. LogicalORExpression : LogicalORExpression || LogicalANDExpression 1. Пусть lref результат вычисления LogicalORExpression. 2. Пусть lval будет результатом GetValue(lref). 3. Пусть lbool результат ToBoolean(lval). 4. Если lbool - true, вернуть lval. 5. Пусть rref это результат вычисления LogicalANDExpression. 6. Вернуть GetValue(rref). В случае || левый операнд приводится к bool и если значение true возвращается сам операнд. В противном случае возвращается правый операнд.

Ответ 3



В javascript такие вопросы решаются очень просто: приведением типов ( в данном случае будет приводится к булевому типу ) Зачем это нужно? В javascript && и || ленивые операторы, то есть они не всегда будут высчитывать все значения. Например: если мы используем &&, то true будет только в том случае, если обе переменные true true && false // false false && false // false true && true // true false && true // false В последнем примере нам даже не обязательно высчитывать значение второй переменной, так как первая false, то мы уже точно знаем, что результат тоже будет false. Этим можно воспользоваться в некоторых ситуациях const element = document.getElementById('id'); // какой-то элемент //теперь представим, что нам нужно что-то сделать с этим элементом // в случае если он есть на странице // можно сделать так if(element) { someFn(element); } // а можно короче воспользовавшись ленивостью оператора && element && someFn(element); // someFn вызовется только если element true В доказательство, что движок даже не смотрит изначально за && в том, что false && arueybgqnreugnqgr(); // все ок То же самое с ||, только его используют для других целей: const fn = param => { return param || 42 // по сути так мы устанавливаем значение по умолчанию } fn(10); // 10 fn(); // 42 fn(0); // тоже 42, потому что !!0 === false Пустая строка, 0, undefined, NaN, null (кажется, ничего не забыл ) - приводятся к false. Остальное к true, причем: !![]; // true !!({}); // true

Как запустить Ubuntu c загрузочного диска на USB / Как вернуться в Windows?

#linux #windows #ubuntu #usb #dual_boot


Буду благодарен за пошаговые инструкции:


Есть загрузочный диск на USB с образом Ubuntu. Как его запустить?
Как после запуска Ubuntu вернуться в Windows?

    


Ответы

Ответ 1



Вопрос: Есть загрузочный диск на USB с образом Ubuntu. Как его запустить? Ответ: Необходимые условия: Подключение к сети интернет, т.к. во время установки будут загружены дополнительные пакеты программ, которые не поместились на установочный образ. Диск или флешка с iso-образом Установка Вставьте диск в дисковод, либо флешку в порт и перезагрузите компьютер. После перезагрузки должно открыться на экране окно приветствия Welcome, где нужно выбрать язык: Когда вы выберите язык, в окне приветствия будет предложено два варианта: Запустить Ubuntu и Установить Ubuntu: Если вы выберите Запустить Ubuntu, то система будет загружена в Live-режиме, т.е. без установки на ж/диск компьютера и можно будет "пощупать" Ubuntu, а в дальнейшем перейти к установке. В случае с выбором Установить Ubuntu, вы перейдёте к непосредственной установке. Предположим вы выбрали Запустить Ubuntu. Должен открыться рабочий стол Ubuntu: После знакомства с Ubuntu, вы можете перейти к непосредственной установке. Двойной клик на значке на рабочем столе - Установить Ubuntu: Если язык выбран вами правильно, нажмите копку Продолжить, чтобы перейти к следующему шагу: В шаге Подготовка к установке Ubuntu, активируйте оба пункта: Загрузить обновления при установке и Установить сторонне программное обеспечение, как на верхнем снимке и Продолжить. В шаге Тип установки нужно выбрать один из трёх типов. У меня установлено несколько систем на жестком диске, у вас может быть одна, но суть от этого не меняется. Если вы не умеете разбивать жесткий диск на разделы, оставьте активированным первый пункт и установщик сам найдет место рядом с установленной системой, не причинив ей ни какого вреда. Либо вы можете выбрать второй вариант, который предлагает Стереть диск и установить Ubuntu. В этом случае сотрётся всё что у вас есть на ж/диске и установится только Ubuntu. И наконец третий вариант - Другой вариант, предлагает создать и изменить разделы самостоятельно для Ubuntu (для опытных пользователей). Выбрав первый пункт Установить Ubuntu рядом с ними, нажмите Продолжить, после чего откроется следующий шаг, где будет предложено автоматическое разбиение пространства на ж/диске, но вы можете поместить курсор в центр, между двух разделов и двигать его, тем самым изменяя размеры разделов. В случае выбора третьего варианта - Другой вариант, вы можете выбрать один из существующих разделов, двойной клик на строке с разделом и в открывшемся окне Изменить раздел, в параметре Использовать как выберите Журналируемая файловая система Ext4; поставьте флажок в параметре Форматировать раздел; Точка монтирования - корневой раздел / (правый слэш) и нажмите ОК, как на нижнем снимке : После того как вы определились с разделами, нажмите Установить сейчас. Откроется окно с пояснениями о том что раздел будет отформатирован и пр. Если вы сомневаетесь или выбрали не тот раздел ж/диска, то есть возможность вернуться и переделать созданный раздел, либо переключиться на другой, нажав кнопку Вернуться. Если всё правильно, нажмите Продолжить, чтобы перейти к следующему шагу. Далее, в окне установки Где вы находитесь? введите в поле внизу окна название вашей местности, либо кликните на карте, для правильного отображения времени в системе и Продолжить. Следующим шагом будет определение Раскладки клавиатуры: Здесь вам предложено выбрать язык раскладки клавиатуры и Продолжить. Откроется приветственное окно, демонстрирующее возможности Ubuntu, с которыми можно познакомиться до окончания установки. Дождитесь окончания установки. Когда установка закончится, откроется последнее окно установщика - Установка завершена. Вопрос: Как после запуска Ubuntu вернуться в Windows? Ответ: Если вы хотите чтоб на вашем ПК нормально работал Windows и Ubuntu. В случае установки с нуля (новый "чистый" ПК), рекомендую сначала устанавливать Windows. В случае установки Ubuntu быстрее Windows будут проблемы. Если у вас уже установлена Windows, смело устанавливайте Ubuntu рядом как вторую ОС. Будте внимательны во время установки в моменте с Разделами После того как Ubuntu будет установлена, вы можете менять системы через клавишу F11, нажимать ее необходимо во время загрузки, когда система начинает загружаться. Хотя еще могут быть разные моменты, но в целом принцип такой.

В чем отличие троеточия от квадратных скобок?

#java #методы #varargs


В чем разница между

private void onProgressUpdate(String... item);


и

private void onProgressUpdate(String[] item);

    


Ответы

Ответ 1



Главное отличие в сигнатуре методов. В первом случае сигнатура метода определяет один или более параметров типа String, во втором передается только один параметр типа String[]. Определение vararg также допускает использование массива в качестве аргумента. В первом случае может быть использовано onProgressUpdate("item1","item2","item3"); или onProgressUpdate(new String[]{"item1","item2","item3"}); а во втором случае только последний вариант. Более подробно об vararg можно почитать здесь.

Ответ 2



Первое, это varargs, что обозначает передачу неограниченного количества элементов. Пример: link void func(int... numbers); func(1,2,3,4,5,6,7,8); Второй, это просто передача массива. Пример: void func(int[] arr); int[] arr = new int[10]; func(arr);

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

#cpp #gcc #x86_64


Елементарный способ: произвести заполнение массива при инициализации. Но массив статический
и уже занимает место в образе. Нужно каким-то образом указать компилятору заполнить
область массива конкретным значением. 
Код static int arr[5]={1} заполняется как {1, 0, 0, 0, 0}, а нужно {1, 1, 1, 1, 1}

__attribute__((fillupper(1))) игнорируется gcc.

Массив неконстантный. Массив с 5 элементами - пример. Нужно заполнить массив в 4096
элементов.
Использование возможностей STL сильно ограничены, включая производные. Они все имеют
элементарное решение, указанное в первом предложении.

Доработка ответа:

template 
struct IArray {
  type val = v;
  IArray& operator=(type n){
    val=n;
    return *this;
  }
  IArray& operator|=(type n){
    val|=n;
    return *this;
  }
};


И необходимо дописать/изменить операторы для нужных Вам преобразований.
    


Ответы

Ответ 1



#include template struct Int { int val = v; }; int main() { Int<10> arr[1024]; std::cout << arr[10].val << std::endl; } https://godbolt.org/z/6-BEPi

Ответ 2



Не бейте меня. Нашёл только asm способ. //> g++ -std=c++11 memset.cpp #include asm( " .globl s2\n" " .data\n" " .align 32\n" " .type s2, @object\n" " .size s2, 16384\n" "s2: .fill 4096,4,777\n" ); extern "C" { extern int s2[4096]; }; int main(){ for(size_t j = 4096+1;j>0;){--j; std::cout<<"s2["<

Ответ 4



dd if=/dev/zero of=/tmp/sarr conv=swab count=4096 xxd -i /tmp/sarr | sed -e 's/0x00/0x01/g' > /tmp/parr.h P.S. :) UPD: #include template class ct_array { public: constexpr explicit ct_array(); public: const T& operator[](size_t idx) const; protected: T m_data[N]; }; template constexpr ct_array::ct_array() : m_data() { for (T *el = m_data; el != m_data + N; ++el) *el = def_val; } template const T& ct_array::operator[](size_t idx) const { return m_data[idx]; } template constexpr decltype(auto) make_ct_array() { return ct_array(); } int main() { constexpr auto arr = make_ct_array(); std::cout << arr[10] << std::endl; return 0; } UPD2: #include template class ct_array { public: constexpr explicit ct_array(T def); public: const T& operator[](size_t idx) const; protected: T m_data[N]; }; template constexpr ct_array::ct_array(T def) : m_data() { for (T *el = m_data; el != m_data + N; ++el) *el = def; } template const T& ct_array::operator[](size_t idx) const { return m_data[idx]; } template constexpr decltype(auto) make_ct_array(T def) { return ct_array(def); } int main() { constexpr auto arr = make_ct_array(3.14); std::cout << arr[10] << std::endl; return 0; }

Ответ 5



Можно написать функцию template void f(T a[], size_t s, const T& n) { for (size_t i = 0; i < s; ++i) a[i] = n; } Тогда const int n = 4096; int arr[n]; f(arr, n, 1); после ее вызова вы получите желаемый результат Или же воспользоваться стандартным альгоритмом const int n = 4096; int arr[n]; std::fill(arr, arr + n, 1);

шаблоны с переменными аргументами

#cpp #шаблоны_с++


Задача:


Принять в функцию неопределенное количество элементов с разными типами.
Засунуть все принятое в stringstream


Вопрос:


Как раскрыть список аргументов и засунуть в stringstream?


Может, нужно использовать другие инструменты для этой задачи? Подскажите пожалуйста
какие(просьба, вариант с ostream не предлагать)?

  template
            void tfunc(const Arguments & ... args)
            {
                std::stringstream ss;
                //ss<


Ответы

Ответ 1



Это легко делается при помощи fold expression: template void tfunc(Arguments const & ... args) { std::stringstream ss; (ss << ... << args); } online compiler

Ответ 2



Вы можете воспользоваться временным массивом для распаковки пакета параметров. template std::string foo(Args const & ... args) { std::stringstream ss; using arr_t = int[sizeof...(args)];//Тип массива для удобства arr_t{((ss << args << ' '), 0)...};//Создаем временный массив return ss.str(); }

Ответ 3



Ну, например, так: void tfunc(stringstream&) {} template void tfunc(stringstream& s, T t, Arguments ... args) { s << t << " "; tfunc(s,args...); } int main(int argc, const char * argv[]) { stringstream s; tfunc(s,1,0.5,",,,"); cout << s.str() << endl; }

Определить стили

#css


Помогите определить стили для Teacher, не меняя HTML.



{
  font-weight: bold;
}




    


Ответы

Ответ 1



ul.one>li:nth-child(2) span { font-weight: bold; animation: 1s ellipse ease-in-out infinite; position: absolute; } @keyframes ellipse { 50% { transform: scale(2); } }

Ответ 2



как вариант { font-weight: bold; } .one li:nth-child(2) { background: red; }

Ответ 3



Любой из перечисленных ниже через запятую, тут может быть очень много вариантов. li:nth-child(2) .four, li:nth-child(2) span, .two:nth-child(2) span, .two:nth-child(2) .four, .two:last-child span, .two:last-child .four { font-weight: bold; }

Ответ 4



.two + .two { font-weight: bold; }

Как сделать чтобы при выборе элемента списка менялся текст абзаца?

#javascript #html #css


Нужно чтобы при выборе определенного li, менялось содержимое p на значение li



var select = document.getElementsByClassName("select");

var company = document.getElementById("company");

select.onclick = select_company;

function select_company() {
  company.innerHTML = "";
};

Выберите компанию

  • Компания 1
  • Компания 2
  • Компания 3


Ответы

Ответ 1



Проблема в том, что у Вас в var select - целая коллекция, поэтому просто так что-то сделать по клику не получится - нужен обход всех элементов этой коллекции: $('.select').each(function(){ $(this).click(function(){ $('#company').text($(this).text()); }) });

Выберите компанию

  • Компания 1
  • Компания 2
  • Компания 3


Ответ 2



Вариант на чистом javascript: let [select, company] = [ [...document.querySelectorAll(".select")], document.querySelector("#company") ]; select.map(elem => elem.addEventListener('click', (e) => { company.innerText = e.target.innerText; }));

Выберите компанию

  • Компания 1
  • Компания 2
  • Компания 3


Ответ 3



Нельзя один id назначать сразу нескольким элементам на страницу, вместо него для элементов лучше используйте class. Вариантов реализации достаточно, например:

Выберите компанию

  • Компания 1
  • Компания 2
  • Компания 3


Откуда функция free знает, сколько конкретно байтов памяти освобождать [дубликат]

#c #память #выделение_памяти


        
             
                
                    
                        
                            На этот вопрос уже даны ответы здесь:
                            
                        
                    
                
                        
                            Откуда C/C++ знает сколько надо освободить памяти, если
не знает размер массива?
                                
                                    (2 ответа)
                                
                        
                                Закрыт 1 год назад.
            
                    
Я новичок в программировании на языке Си. Вопрос по поводу работы функции free стандартной
библиотеки stdlib.h. Допустим, я выделил память для 100 символов:

char *pointer = malloc(100 * sizeof(char));


А как грамотно освободить эту память? Необходимо освобождать каждый char

for (int i = 0; i < 100; i++) free(pointer[i]);


или достаточно

free(pointer);


одним вызовом функции free? Я склоняюсь ко второму варианту, поскольку значение pointer[i]
из первого варианта не является указателем. Но откуда функция free знает, сколько памяти
я выделил через malloc? Это где-то записано в оперативной памяти или здесь используется
какая-то хитрость?
    


Ответы

Ответ 1



free(pointer); вполне достаточно. Диспетчер памяти сам разберется, сколько памяти освободить. Он хранит эту информацию где-то в своих внутренних структурах. Как именно - зависит от конкретной реализации. Например, как вариант - вы запрашиваете malloc, при этом выделяется памяти чуть больше - ну, на какие-то, скажем, 4-8 байт, и вам возвращается указатель, смещенный на эти 4-8 байт, в которые менеджер записывает длину (и не только - если памяти выделить побольше:)). А при освобождении - он отсчитывает от переданного указателя нужное число байт и читает сохраненную информацию. Еще раз - написанное не означает, что все сделано именно так, это всего лишь один из возможных вариантов. Как именно выделять память и где хранить служебную информацию - стандарт не определяет. Если вы хотите писать переносимые программы - вас это интересовать (для применения в своем коде) не должно...

Ответ 2



malloc поддерживает внутренную структуру, в которой хранит кроме прочего и размеры всех выделенных кусков памяти. В glibc есть интерфейс для доступа к этой информации: size_t malloc_usable_size(void*). Ну и вообще там много интересного: https://www.gnu.org/software/libc/manual/html_node/Summary-of-Malloc.html#Summary-of-Malloc

Ответ 3



Процесс освобождения памяти должно "зеркально" соответствовать процессу его выделения. В данном случае вы выделяли память одним вызовом malloc. Значит освобождать вы ее будете одним вызовом free. Ни о каком "освобождать каждый char" не может быть и речи. В традиционной реализации, malloc выделит больше памяти, чем вы запросили. В дополнительные байты памяти (обычно в начале выделенного блока) будет записан размер выделенного блока памяти +-----+-------------------------- ----+ | 100 | ... | +-----+-------------------------- ----+ ^ ^ ^ | | адрес, который `malloc` вернет вам в качестве результата | | | размер блока, записанный туда `malloc` | начало фактически выделенного `malloc` блока Когда вы вызовете free(pointer), функция free просто прочтает размер блока из области памяти "слева" от адреса pointer - так она узнает, сколько памяти нужно освободить. Вот и вся "хитрость". Записанный размер может быть полным размером блока или полезным размером блока, а также может меняться в большую сторону из соображений выравнивания размеров блоков. Это все детали реализации, как, впрочем, и весь механизм.

Как разместить 2 блока, чтобы один был справа от другого и растягивался на всю оставшуюся ширину?

#html #css #вёрстка


Вот чего нужно добиться:


Есть внешний блок 
, его размеры зависят в процентах от размера окна. Внутри него расположены еще 2
. Первый из них имеет фиксированные размеры, а второй должен находиться справа от первого и растягиваться на всю оставшуюся ширину внешнего блока. Кроме того, у второго внутреннего блока установлена еще и минимальная ширина. Если ширина внешнего блока станет меньше, чем ширина первого внутреннего + минимальная ширина второго, тогда второй блок должен съезжать вниз и располагаться под первым. Т.к. у первого блока ширина фиксированная и он один теперь не может заполнить всю линию от края до края, поэтому он должен стать по середине. Т.е. второй внутренний блок должен переноситься вниз только когда достигнет предела и не сможет больше уменьшаться, до тех пор он должен быть справа от первого блока.


Ответы

Ответ 1



.parent { display: flex; flex-wrap: wrap; justify-content: center; } .inner-left { width: 150px; outline: 1px solid #060; } .inner-right { flex-basis: 250px; flex-grow: 1; outline: 1px solid #900; }
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Provident doloribus corporis minima delectus illum, quaerat iure cumque maxime ut, nihil recusandae asperiores tempora architecto! Minima magnam reiciendis nam voluptatum quia. Lorem ipsum dolor sit amet, consectetur adipisicing elit.
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quidem dolores, fugit libero, quaerat officia cupiditate itaque natus dolor adipisci sit possimus neque fuga ea et, repellat tempora consequatur nostrum ut! Doloribus consequuntur enim iure nesciunt quo aliquid. Repellendus sint praesentium, incidunt fugiat doloremque aperiam ullam ad, possimus animi asperiores provident quasi iste. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quam ipsam voluptatem architecto corporis exercitationem, velit veritatis ab dolorem vitae nihil eaque iusto labore dolore deleniti nesciunt possimus vero amet consectetur.
flex-basis: 250px; тут играет роль минимальной ширины, описанной вами в третьем пункте P.S. Пардон, забыл сразу вендорные префиксы дописать: .parent { display: -webkit-box; display: -ms-flexbox; display: flex; -ms-flex-wrap: wrap; flex-wrap: wrap; -webkit-box-pack: center; -ms-flex-pack: center; justify-content: center; } .inner-left { width: 150px; outline: 1px solid #060; } .inner-right { -ms-flex-preferred-size: 250px; flex-basis: 250px; -webkit-box-flex: 1; -ms-flex-positive: 1; flex-grow: 1; outline: 1px solid #900; }

Ответ 2



Например: * { box-sizing:border-box; } html, body { padding: 0; margin: 0; } .wrap { display: flex; flex-flow: row wrap; } .left { width: 50px; flex-grow: 0; flex-shrink: 0; background: #888; } .right { min-width: 100px; background: #ccc; width: calc(100% - 50px); }
Left
Right
caniuse flexbox caniuse calc

Ответ 3



.wrapper { display: grid; grid-template-columns: 100px auto; border: 1px green solid; min-width: 300px; } .const , .flex { display: inline-block; height: 80px; margin: 15px; box-sizing: border-box; } .const { width: 80px; border: 1px red solid; } .flex { min-width: 160px; border: 1px blue solid; } @media screen and (max-width: 310px) { .wrapper { grid-template-columns: auto; justify-items: center; min-width: auto; } .flex { min-width: calc(100% - 30px); } }
решение на grid-ах

Фрагментация картинки с возможностью перемещения каждого фрагмента

#javascript #html #css #svg #анимация


Суть вопроса в заголовке, добавлю только, что не важно какие теги и css будет использован(или
даже js, но лучше без него), главное фрагменты картинок можно было перемещать.

Что-то похожее есть, но это решение не подходит
    


Ответы

Ответ 1



Находим картинку по вкусу Габаритные размеры - 813 x 514px .imgWrap .left { left: 0; background-position: 3% 0; } .imgWrap .center{ left:34.83%; background-position: -87% 0; } .imgWrap .right { left:69.66%; background-position:-157% 0; } За придания объема картинке отвечают: .imgWrap > div:before{ content:''; position:absolute; top:0;right:100%; width:10%; height:100%; background:inherit; transform-origin:100% 50%; transform:rotateY(-90deg); } body{perspective:1000px;} .imgWrap{ position:relative; width:80%; margin:5% auto; padding-bottom:39%; transform: rotateY(25deg); transform-style:preserve-3d; } .imgWrap > div{ position:absolute; top:20%; width:30.3%;height:100%; float:left; background-image:url('https://i.stack.imgur.com/ZE0fb.jpg'); background-size:auto 100%; transform-style:preserve-3d; outline: 2px solid transparent; */ } .imgWrap .left { left: 0; background-position: 3% 0; } .imgWrap .center{ left:34.83%; background-position: -87% 0; } .imgWrap .right { left:69.66%; background-position:-157% 0; } .imgWrap > div:before{ content:''; position:absolute; top:0;right:100%; width:10%; height:100%; background:inherit; transform-origin:100% 100%; transform:rotateY(-90deg); } .imgWrap .left:before { background-position: 0% 0; } .imgWrap .center:before{ background-position: -1001.3% 0; } .imgWrap .right:before { background-position: -2001.4% 0; }


Ответ 2



SVG решение SVG решение - должно быть по определению, - адаптивно. Чтобы приложение было адаптивно и не разрушались пропорции между фрагментами изображения необходимо сделать следующее: Изображение добавляется внутрь svg с помощью команды и задаются размеры его в процентах width="100%" height="100" Окна вырезать комбинированной маской. При присвоении одним частям маски fill="white" она будет прозрачна и в вырезанных окошках будут видны фрагменты изображения. Закраска fill="black" делает участок маски непрозрачным - это белые перемычки между окнами. Более подробно и просто о масках здесь Обернуть svg
в родительский контейнер. Изменяя проценты ширины и высоты контейнера можно регулировать начальные размеры блока. .container { width:100%; height:100%; }
Анимация фрагментов изображения При наведении курсора на картинку фрагменты изображения сливаются в целое изображение. Это обеспечивает команда анимации добавленная в маску: Реализация смещения фрагмента изображения (секции маски) осуществляется изменением координаты левого верхнего угла прямоугольника - X values="210;189" При уходе курсора с картинки, изображение возвращается к исходному состоянию : .container { width:100%; height:100%; }


Функция slice не работает для document.querySelector. Ошибка .slice is not a function

#javascript #queryselector


Что-то запутался. Почему так? как исправить?

var longtext = document.querySelector('.excerpt>p:nth-child(2)');// 

long long text

var cuttext = longtext.slice(0, 40); // Uncaught TypeError: longtext.slice is not a function if (cuttext.length < longtext) { cuttext += "..."; }


Ответы

Ответ 1



Используемый метод document.querySelector возвращает только один элемент, а не массив. Поэтому дальнейшая попытка взять первые сорок элементов(?) из одного выглядит странно. Чтобы получить коллекцию элементов необходимо воспользоваться методом document.querySelectorAll. Которая возвращает коллекцию подходящих элементов, однако, у возвращаемой коллекции отсутствует метод slice, и чтобы его применять нужно либо одолжить его у массива, либо преобразовать полученную коллекцию непосредственно в массив, например с помощью Array.from var longtext = Array.from(document.querySelectorAll('.excerpt>p:nth-child(2)')); var cuttext = longtext.slice(0,40); //Uncaught TypeError: longtext.slice is not a function if (cuttext.length < longtext.length) { cuttext+="..."; } Однако, судя по названию переменных, можно предположить что работа ожидается с текстом, а не html элементами. В этом случае, чтобы получить текст выбранного элемента необходимо было воспользоваться методом textContent, либо если нужно получить текст включая html-теги, innerHTML var longtext = document.querySelector('.excerpt>p:nth-child(2)').textContent;//long long text var cuttext = longtext.slice(0,40); //Uncaught TypeError: longtext.slice is not a function if (cuttext.length < longtext.length) { cuttext+="..."; }

Ответ 2



cuttext в твоем варианте это не массив, а html collection. переведи html collection в массив, потом сделай слайс var arr = Array.prototype.slice.call( longtext ) var cuttext = arr.slice(0,40); в итоге твой код: используя ES2015, я обычно делаю так: var arr = [...longtext];

“Достать” элемент из списка

#python


Из списка:

lst = [{
  'update_id': 138638308, 
  'message': {
    'message_id': 215, 
    'from': {
      'id': 2999, 
      'is_bot': False, 
      'first_name': 'Yuri'}, 
    'chat': {
      'id': 77777777, 
      'first_name': 'Yuri'}
    }
  }]


"достать" 'id': 77777777 и показать в формате 77777777.
Как это сделать?
    


Ответы

Ответ 1



Смотрите, постепенно (результат - lst[0]['message']['chat']['id'] - в конце): lst[0] lst[0]['message'] lst[0]['message']['chat'] lst[0]['message']['chat']['id'] В консоли: In[16]: lst = [{'update_id': 138638308, 'message': {'message_id': 215, 'from': {'id': 2999, 'is_bot': False, 'first_name': 'Yuri'}, 'chat': {'id': 77777777, 'first_name': 'Yuri'}}}] In[17]: lst[0] Out[17]: {'message': {'chat': {'first_name': 'Yuri', 'id': 77777777}, 'from': {'first_name': 'Yuri', 'id': 2999, 'is_bot': False}, 'message_id': 215}, 'update_id': 138638308} In[18]: lst[0]['message'] Out[18]: {'chat': {'first_name': 'Yuri', 'id': 77777777}, 'from': {'first_name': 'Yuri', 'id': 2999, 'is_bot': False}, 'message_id': 215} In[19]: lst[0]['message']['chat'] Out[19]: {'first_name': 'Yuri', 'id': 77777777} In[20]: lst[0]['message']['chat']['id'] Out[20]: 77777777

Ответ 2



from functools import reduce, wraps def silenced(*exceptions): def decorator(f): @wraps(f) def wrapper(*args, **kwargs): try: return f(*args, **kwargs) except exceptions: return None return wrapper return decorator @silenced(IndexError, KeyError) def item_getter(container, key): if container is not None: return container[key] lst = [{ 'update_id': 138638308, 'message': { 'message_id': 215, 'from': { 'id': 2999, 'is_bot': False, 'first_name': 'Yuri'}, 'chat': { 'id': 77777777, 'first_name': 'Yuri'} } }] path = [0, 'message', 'chat', 'id'] value = reduce(item_getter, path, lst) print(value)

Ответ 3



Как вариант - анализировать (доставать) в словаре: d = {} lst = [{'update_id': 138638308, 'message': {'message_id': 215, 'from': {'id': 2999, 'is_bot': False, 'first_name': 'Yuri'}, 'chat': {'id': 77777777, 'first_name': 'Yuri'}}}] for tsl in lst: d.update(tsl) d['message']["chat"]['id']

Ответ 4



Предполагая что lst может содержать несколько словарей (вероятно, это приходящие откуда-то данные), можно перебором, например: >>> lst = [ # Первый словарь {'update_id': 138638308, 'message': {'message_id': 215, 'from': {'id': 2999, 'is_bot': False, 'first_name': 'Yuri'}, 'chat': {'id': 77777777, 'first_name': 'Yuri'}}}, # Второй словарь {'update_id': 138638309, 'message': {'message_id': 215, 'from': {'id': 2999, 'is_bot': False, 'first_name': 'Yuri'}, 'chat': {'id': 786313456456, 'first_name': 'Yuri'}}}, # Третий словарь {'update_id': 138638310, 'message': {'message_id': 215, 'from': {'id': 2999, 'is_bot': False, 'first_name': 'Yuri'}, 'chat': {'id': 874454646, 'first_name': 'Yuri'}}} ] # И сколько угодно может быть словарей >>> for item in lst: id = item['message']["chat"]['id'] # В переменную id сохраняем нужное значение и делаем внутри цикла всё что нужно с ней. print(id) # Вывод 77777777 786313456456 874454646

Ответ 5



print(lst[0]['message']['chat']['id'])

Клик по картинке на js

#javascript #jquery #canvas


Как сделать на js клик по картинке? попытался через jquery, но не срабатывает.



var cvs=document.getElementById("canvas"); // подключаем полотно для отображения кода
var ctx = cvs.getContext("2d"); 
var image1=new Image(); // добавляем картинку 

image1.src="https://cdn.pixabay.com/photo/2018/03/08/21/49/lighthouse-3209985_960_720.jpg";
 // адрес картинка

function  q92(){ 
    ctx.drawImage(image1,0,0); 
}

image1.onload=q92; // когда картинка загрузится отрисовываем её
image1.class="qwer";

$('.qwer').on("click", function() {// функция которая должна рабоатать при клике
но не работает 
  alert("adsads");
});

 



    


Ответы

Ответ 1



Image, который Вы создали, не вставлен в DOM страницы. Поэтому щелкнуть по нему - невозможно. Канвас, напротив, является элементом DOM. var cvs = document.getElementById("canvas"); // подключаем полотно для отображения кода var ctx = cvs.getContext("2d"); var image1 = new Image(); // добавляем картинку image1.src = "https://cdn.pixabay.com/photo/2018/03/08/21/49/lighthouse-3209985_960_720.jpg"; // адрес картинка function q92() { ctx.drawImage(image1, 0, 0); } image1.onload = q92; // когда картинка загрузится отрисовываем её $(cvs).on("click", function() { // функция, которая должна работать при клике, и работает alert("adsads"); }); Без канваса: var image1 = new Image(); // добавляем картинку image1.src = "https://cdn.pixabay.com/photo/2018/03/08/21/49/lighthouse-3209985_960_720.jpg"; // адрес картинка document.body.appendChild(image1); $(image1).on("click", function() { // функция, которая должна работать при клике, и работает alert("adsads"); });

Ответ 2



Определяем в какую конкретно картинку, нарисованную на канве произошел клик. Этот метод называется picking часто используется в трехмерной графике для определения что же под мышкой, для 2д тоже отлично подходит. Суть в том, чтобы параллельно с отрисовкой картинок на канве мы формируем дополнительный буфер, в котором интересующие нас объекты (картинки) закодированы разным цветом-идентификатором, а по клику берем цвет по координатам клика из пикинг-буфера. UPD: добавил анимацию let imagesCanvas = document.querySelector('canvas'); let pickingCanvas = document.createElement('canvas'); pickingCanvas.width = imagesCanvas.width; pickingCanvas.height = imagesCanvas.height; let imgCtx = imagesCanvas.getContext('2d'); let pickCtx = pickingCanvas.getContext('2d'); imgCtx.strokeStyle = 'red'; imgCtx.lineWidth = 4; let images = ['11', '22','33' ] let loaded = []; let current = -1; // слушатель вешаем на канву imagesCanvas.addEventListener('click', (e) => { // берем цвет по координатам и вычисляем из него индекс var i = pickCtx.getImageData(e.x, e.y, 1, 1).data["0"]-1; current = loaded[i] ? i : -1; }) load();// загружаем картинки function load() { let name = images.shift(); let img = new Image(); img.crossOrigin = "anonymous"; // вызываем загрузку следующей картинки, пока они все не будут загружены, // тут надо предусмотреть onerror, и отрисовку, когда они все загрузятся img.onload = () => add() | images.length ? load() : requestAnimationFrame(draw); img.src = `https://picsum.photos/id/${name}/150/100` // добавляем инфо о картинке в массив function add() { loaded.push({ name: name, img: img, // кодируем индекс картинки в цвет pickingColor: `rgb(${loaded.length+1},0,0)`, x: 50+loaded.length*120, y: 5+30*loaded.length, w: img.width, h: img.height }); } } let t = 0; function draw(dt) { pickCtx.clearRect(0, 0, imagesCanvas.width, imagesCanvas.height); imgCtx.clearRect(0, 0, imagesCanvas.width, imagesCanvas.height); loaded.forEach((img, i) => { img.x += (dt-t)*(i/10+1)/10; img.x = img.x > 600 ? 0 : img.x; // рисуем картинки на канве imgCtx.drawImage(img.img, img.x , img.y, img.w, img.h); i === current && imgCtx.strokeRect(img.x, img.y, img.w, img.h); // заполняем пикинг-буфер такими же по размеру прямоугольниками // как и картинки на канве и по тем же координатам pickCtx.fillStyle = img.pickingColor; pickCtx.fillRect(img.x, img.y, img.w, img.h); }); t = dt; requestAnimationFrame(draw); } body{margin:0} связанный ответ: https://ru.stackoverflow.com/a/988105/188366

Ответ 3



var cvs=document.getElementById("canvas"); // подключаем полотно для отображения кода var ctx = cvs.getContext("2d"); var image1=new Image(); // добавляем картинку image1.src="https://cdn.pixabay.com/photo/2018/03/08/21/49/lighthouse-3209985_960_720.jpg"; // адрес картинка function q92(){ ctx.drawImage(image1,0,0); image1.click(); } image1.onload=q92; // когда картинка загрузится отрисовываем её image1.class="qwer"; $(image1).on("click", function() {// функция которая должна рабоатать при клике но не работает alert("adsads"); });