• Как оптимизировать работу с файлами в Python?

    Или лучше в VBA погрузиться для решения подобных задач?

    VBA - однопоточный, расспаралелить не получится.

    но если только собрать названия листов, то странно большое время у Вас для такой задачи.
    Я тут на коленке набросал код на VBA, так он 200 файлов за 4 минуты обработал, и это без оптимизации кода (excel 32, win 10, 4ядра по 3ГГц).
    Можете запустить у себя, для этого открыть новую книгу, открыть редактор макросов, выбрать лист на котором будете работать и вставить следующий код (полной заменой)
    Код для сбора списка листов из всех книг директории
    Function FilenamesCollection(ByVal FolderPath As String, Optional ByVal Mask As String = "", _
                                 Optional ByVal SearchDeep As Long = 999) As Collection
        ' © EducatedFool  excelvba.ru/code/FilenamesCollection
        ' Получает в качестве параметра путь к папке FolderPath,
        ' маску имени искомых файлов Mask (будут отобраны только файлы с такой маской/расширением)
        ' и глубину поиска SearchDeep в подпапках (если SearchDeep=1, то подпапки не просматриваются).
        ' Возвращает коллекцию, содержащую полные пути найденных файлов
        ' (применяется рекурсивный вызов процедуры GetAllFileNamesUsingFSO)
    
        Set FilenamesCollection = New Collection    ' создаём пустую коллекцию
        Set FSO = CreateObject("Scripting.FileSystemObject")    ' создаём экземпляр FileSystemObject
        GetAllFileNamesUsingFSO FolderPath, Mask, FSO, FilenamesCollection, SearchDeep ' поиск
        Set FSO = Nothing     ' очистка строки состояния Excel
    End Function
     
    Function GetAllFileNamesUsingFSO(ByVal FolderPath As String, ByVal Mask As String, ByRef FSO, _
                                     ByRef FileNamesColl As Collection, ByVal SearchDeep As Long)
        ' перебирает все файлы и подпапки в папке FolderPath, используя объект FSO
        ' перебор папок осуществляется в том случае, если SearchDeep > 1
        ' добавляет пути найденных файлов в коллекцию FileNamesColl
        On Error Resume Next: Set curfold = FSO.GetFolder(FolderPath)
        If Not curfold Is Nothing Then    ' если удалось получить доступ к папке
    
            ' раскомментируйте эту строку для вывода пути к просматриваемой
            ' в текущий момент папке в строку состояния Excel
            ' Application.StatusBar = "Поиск в папке: " & FolderPath
    
            For Each fil In curfold.Files    ' перебираем все файлы в папке FolderPath
                If fil.Name Like "*" & Mask Then FileNamesColl.Add fil.Path
            Next
            SearchDeep = SearchDeep - 1    ' уменьшаем глубину поиска в подпапках
            If SearchDeep Then    ' если надо искать глубже
                For Each sfol In curfold.SubFolders    ' перебираем все подпапки в папке FolderPath
                    GetAllFileNamesUsingFSO sfol.Path, Mask, FSO, FileNamesColl, SearchDeep
                Next
            End If
            Set fil = Nothing: Set curfold = Nothing    ' очищаем переменные
        End If
    End Function
    
    Sub LoopThroughFiles(ByVal sDirName As String, ByRef lRow As Long, ByVal sMask As String)
       On Error Resume Next
       Dim folder$, coll As Collection
       Dim EX As Excel.Application
       Dim wkb As Workbook
       Dim wks As Worksheet
       Dim file As Variant
       Dim i As Long
       Dim v As Variant
       
     
        folder$ = sDirName
        If Dir(folder$, vbDirectory) = "" Then
            MsgBox "Не найдена папка «" & folder$ & "»", vbCritical
            Exit Sub        ' выход, если папка не найдена
        End If
     
        Set coll = FilenamesCollection(folder$, sMask)        ' получаем список файлов по маске из папки
        If coll.Count = 0 Then
    '        MsgBox "В папке «" & Split(folder$, "\")(UBound(Split(folder$, "\")) - 1) & "» нет ни одного подходящего файла!", _
                   vbCritical, "Файлы для обработки не найдены"
            Exit Sub        ' выход, если нет файлов
        End If
     
       Set EX = New Application
       EX.Visible = False
       
       ' перебираем все найденные файлы
       For Each file In coll
        
          Cells(lRow, 2) = CStr(file)
          
          Set wkb = EX.Workbooks.Open(Filename:=file)
    
          ' Если книга не пуста
          If wkb.Sheets.Count > 0 Then
             i = 1
             ReDim v(1 To wkb.Sheets.Count)
             ' Получаем названия листов
             For Each wks In wkb.Sheets
                v(i) = wks.Name
                i = i + 1
             Next wks
    
          End If
    
          Cells(lRow, 3) = Join(v, ",")
    
          wkb.Close False
                
          DoEvents
          
          lRow = lRow + 1
        
          DoEvents
        Next file
        
       Set wks = Nothing: Set wkb = Nothing: Set EX = Nothing
       Set colShts = Nothing
        
    End Sub
    
    Sub LoopThroughDirs()
       Dim lLastRow As Long
       Dim lRow As Long
       Dim i As Long
       Dim v As Variant
       Dim dTime As Double
    
       lRow = 2
       lLastRow = Cells(Rows.Count, 1).End(xlUp).Row
       
       v = Range(Cells(2, 1), Cells(lLastRow, 2))
       
       dTime = Time()
       For i = LBound(v) To UBound(v)
          Application.StatusBar = "Обрабатывается директория " & i & " из " & UBound(v)
          Call LoopThroughFiles(v(i, 1), lRow, "*.xls")
          Call LoopThroughFiles(v(i, 1), lRow, "*.xlsx")
          Call LoopThroughFiles(v(i, 1), lRow, "*.xlsm")
          DoEvents
       Next i
       MsgBox "Готово за " & CStr(CDate(Time() - dTime))
    End Sub


    для запуска в первой колонке заполнить директории которые он будет смотреть. Просматриваются вложенные директории до 999 грубины.

    Запустить процедуру LoopThroughDirs, для этого поставить курсор на название и нажать F5

    Результат
    5f05adc35867d361594006.png
    Ответ написан
    1 комментарий
  • Когда следует создавать функции?

    oshliaer
    @oshliaer Куратор тега Google Apps Script
    Google Products Expert
    Пример заметного количества функций https://github.com/contributorpw/lodashgs/blob/mas... Время работы скрипта растет минимально. Многие пользуются. Дело не в размере. Тем более, что скрипты хорошенько сжимаются перед исполнением. И вот этот файл https://github.com/contributorpw/alasqlgs/blob/mas... (не открывать при медленной сети) работает нормально даже в качестве пользовательской функции, а там, на секундочку, всего полминуты времени исполнения.

    Вы привели в примере SpreadsheetApp.flush(). Этот метод останавливает все расчеты и пересчитывает все, что находится у вас в Таблице. Вероятно, из-за него у вас и проблемы.

    Судя по предыдущим вашим вопросам, вы усиливаете работу интерфейса, давите на впечатление. Ну, так в браузере оно будет работать так как будет работать, и заставить это всё работать быстрее не получится.

    Совет. Откажитесь от
    Всё выделяется сразу. Теперь видно с каким диапазоном работаю. Намного более понятно что попадает в значения диапазона.

    , потому что это все ерунда, и никому не надо смотреть на экран, чтобы понимать, что там работает, а что нет. Пользователю нужно знать три вещи:
    1. Еще не считало
    2. Еще считает
    3. Уже посчитало

    Остальное для него мрак и туман, а вы тратите на них время.
    Ответ написан
    7 комментариев
  • Как изменить привязанный к Google таблице скрипт извне?

    oshliaer
    @oshliaer Куратор тега Google Apps Script
    Google Products Expert
    Это можно сделать через Script API



    Есть куча тонкостей, которые связывает история разработки сервиса, поэтому, если у вас есть в среде nodejs, то я бы рекомендовал использовать cli для проектов Google Apps Script @google/clasp.
    Ответ написан
    1 комментарий
  • Как определить коэффициент влияния погоды?

    @dmshar
    Во-первых. "Влияние" одного параметра на другой может быть оценен с помощью коэффициента корреляции. В данном случае - скорее всего - коэффициента корреляции Присона.
    Во-вторых, "влияние" одного параметра на другой может быть выявлено в виде регрессионной модели.
    Коэффициент корреляции просто покзывает, можно ли ПРЕДПОЛОЖИТЬ, что параметры между собой связаны. Регрессионный подход пытается строить модели. Но что-бы эта модель была адекватной, т.е чтобы с ее помощью можно было действительно что-то предугадывать, на данные должны быль наложены более серьезные ограничения. Выполняются-ли они на ваших данных - надо проверять.
    Другое дело, что в реалии все намного сложнее. Данные у вас (предположим) объем продаж в зависимости от реальной температуры в этот день. А строить модели вы собираетесь по прогнозу. И это вовсе не одно и тоже. И - если подходить серьезно -гораздо сложнее прямой задачи.
    Ну и кроме того, не забывайте, что ваши данные скорее всего имеют еще и сезонную составляющую, причем слово "сезонный" тут может иметь значение и 7 дней, и 30 дней и 365 дней. И если все делать "по взрослому" - то тут уже начинают работать модели временнЫх рядов.
    Ответ написан
    Комментировать
  • Какой новый процессор подойдёт на Acer Aspire 5650?

    @lonelymyp
    Хочу вылезти из минуса по карме.
    У T2050 шина 533, с такой шиной можно максимум T2450 поставить, но между ними разница ничтожно мала, поэтому нет смысла даже пробовать.
    В тырнете есть упоминания об этом буке с процом на 667 шине, что вселяет оптимизм и тогда максимум можно воткнуть T2700, но он стоит 2.5 тыщи на алиэкспрессе, это безумная цена для такого говна.
    Поэтому делаем шаг назад и смотрим на T2600, а он у китайцев уже всего 700 рублей.
    T2600 почти равен T2700 поэтому его и стоит брать.

    Даже с максимальным апгрейдом бук не станет работать шустро, не стоит ждать рассчитывать на многое.
    Само собой необходимо заменить диск на SSD, можно взять самый дешевый, разницы нет.

    Насчёт T7600 и других которые Core 2 Duo (а T2050 это просто Core Duo, без двоечки) сложно сказать, вроде как можно, но я не уверен. Проверяется методом тыка, если включился - считай повезло.
    Опять же логика выбора простая, T7600 это топ и он дорогой, T7400 предпоследний и он дешевый, если брать для пробы то T7400, так как разницы нет.

    По названию можно определить шину, 533 у процессоров кончающихся на 50.
    667 шина лучше, у процессоров с такой шиной название кончается на 00.
    Ответ написан
    Комментировать
  • Как создать триггер для запуска программы в назначенное время?

    oshliaer
    @oshliaer Куратор тега Google Apps Script
    Google Products Expert
    Чтобы не терять триггерное время, а оно очень лимитировано для обычных аккаунтов, лучше всего использовать самовоспроизводящийся триггер

    /**
     *
     */
    function runOnce() {
      trigger_();
    }
    
    /**
     *
     */
    function trigger_() {
      try {
        triggerAction();
      } catch (error) {
        console.error(error.message, error);
      } finally {
        var hours = 10;
        var minutes = 17;
        var seconds = 56;
        var now = new Date();
        var nextTime = new Date();
        nextTime.setHours(0, 0, 24 * 3600 + hours * 3600 + minutes * 60 + seconds);
        var delta = nextTime.getTime() - now.getTime();
        ScriptApp.newTrigger('trigger_')
          .timeBased()
          .after(delta)
          .create();
      }
    }
    
    /**
     *
     */
    function triggerAction() {
      console.log("I'm fine");
    }


    triggerAction - это то, что выполняет ваш скрипт
    runOnce - это то, что вы должны запустить один раз при первом запуске вашего триггера. Другие настройки не требуются
    trigger_ - это и триггер и конфигурация вашего триггера

    Такой триггер выполняется с высокой степенью точности, погрешность часто составляет меньше половины секунды.
    Ответ написан
    Комментировать
  • Какой nfc модуль для arduino выбрать?

    NeiroNx
    @NeiroNx
    Программист
    На самом деле NFC это потомок RFID 13.5 мГц - тоесть было/есть много разных RFID 125 кГц, 13.5 мГц, 900 мГц.
    Но NFC базируется на протоколоах 13.5 мГц - какие то процедуры обмена общие, кодирование данных, модуляция. В целом похоже, но не оно. RFID умел лишь передать свой ИД и так по мелочи, а NFC это уже двухсторонний обмен данными и в этот обмен входит и передача того самого ИД.
    Ответ написан
    Комментировать
  • Как в Utilites.formatDate() задать русскую локаль?

    oshliaer
    @oshliaer Куратор тега Google Apps Script
    Google Products Expert
    Не помню, чтобы Utilities поддерживали локали.

    Для V8 можно использовать DateTimeFormat

    function myFormatDate(date) {
      const y = new Intl.DateTimeFormat('ru',{
        year: 'numeric'
      }).format(date)
      const m = new Intl.DateTimeFormat('ru',{
        month: 'long'
      }).format(date)
      return `${m}-${y}`
    }
    
    function test(){
      const date = new Date();
      console.log(Utilities.formatDate(date, "GMT+3", "MMM-yyyy"));
      console.log(myFormatDate(date));
    }


    По идее, не нужно беспокоиться о производительности в таких местах, в основном они хорошо оптимизируются системой.

    Обратите внимание на свой пример, "MMM-d" не вернет год - вернет дату.
    Ответ написан
    Комментировать
  • Как форматировать результаты скрипта для вывода?

    oshliaer
    @oshliaer Куратор тега Google Apps Script
    Google Products Expert
    Рекомендую использовать метод getDisplayValues()

    var drr = sheet.getRange(sheet.getLastRow(), 1, 1, 3).getDisplayValues()[0];


    т.о. вам не придется беспокоится о типах данных в коде, и будет достаточно привести тип данных в ячейке. Если в ячейке будет видно 0.00%, то вернет именно 0.00%, если 1-02-20, то 1-02-20.

    Это наименьшее и наиболее надежное решение в данном случае.
    Ответ написан
    1 комментарий
  • Моноколесо своими руками, что нужно?

    @lonelymyp
    Хочу вылезти из минуса по карме.
    БУ гироскутер на авито может обойтись дешевле, зато он точно поедет.
    Ответ написан
    Комментировать
  • Как быстрее всего получить данные из сторонних таблиц?

    oshliaer
    @oshliaer Куратор тега Google Sheets
    Google Products Expert
    К сожалению нельзя дать однозначный ответ на этот вопрос. Я бы разделил по способам применения.

    Например, используя формулы мы не получаем набор данных, мы видим лишь их представление. Т.н. представление по ссылке. Мы не можем менять эти данные. Накладывает большие ограничения.

    Программное получение данных является хорошей альтернативой. Но недешевой в плане эксплуатации и поддержки.

    Использование стороннего сервиса. Из адекватных предпочитаю sheetgo.

    Использование Google Apps Script. Там возможны варианты: SpreadsheetApp или Sheet Advanced Service. Для больших данных второй предпочтительнее, но не такой удобный как первый.

    Использование Google Sheets API. Очень напоминает Sheet Advanced Service, но требует своей исполнительной среды и прочих накладных расходов.

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

    Но без худа не бывает чуда. Попробуйте какой-нибудь более-менее пригодный пример для Sheet Advanced Service или подобрать сниппет тут google-apps-script-snippets

    С уважением.
    Ответ написан
    Комментировать
  • Почему программа не срабатывает так, как ожидается при изменении всего одной типовой команды?

    oshliaer
    @oshliaer Куратор тега Google Apps Script
    Google Products Expert
    Перед тем, как копировать формулы в значения вам нужно завершить все расчеты в Таблице.

    Вызовите flush()

    SpreadsheetApp.flush();

    Например,

    /**
     *
     * @param {GoogleAppsScript.Events.SheetsOnEdit} e
     */
    function onEdit(e) {
      var activeSheet = e.source.getActiveSheet();
      SpreadsheetApp.getActive().toast(['Лист'].indexOf(activeSheet.getName()));
      if (['Лист'].indexOf(activeSheet.getName()) == -1) return;
      var r = SpreadsheetApp.getActiveRange();
      var cols = r.getColumn();
      if (cols == 6) {
        // если изменяем 6 колонку, то тригер работает и:
        var cell1 = activeSheet.getRange(2, 2); // во второй колонке берет данные из второй строки (там лежит формула)
        var destination1 = activeSheet.getRange(activeSheet.getLastRow(), 2); // находит последнюю строку с данными и выбирает вторую колонку
    
        cell1.copyTo(destination1); // копирует из второй строчки в последнюю
        var cell2 = activeSheet.getRange(2, 3); // тоже самое но только для 3 колонки
        var destination2 = activeSheet.getRange(activeSheet.getLastRow(), 3); // тоже самое но только для 3 колонки
        cell2.copyTo(destination2); // тоже самое но только для 3 колонки
        var cell3 = activeSheet.getRange(2, 5); // тоже самое но только для 5 колонки
        var destination3 = activeSheet.getRange(activeSheet.getLastRow(), 5); // тоже самое но только для 5 колонки
        cell3.copyTo(destination3); // тоже самое но только для 5 колонки
        var cell4 = activeSheet.getRange(2, 8); // тоже самое но только для 8 колонки
        var destination4 = activeSheet.getRange(activeSheet.getLastRow(), 8); // тоже самое но только для 8 колонки
        cell4.copyTo(destination4); // тоже самое но только для 8 колонки
    
        SpreadsheetApp.flush();
    
        destination1.copyTo(
          destination1,
          SpreadsheetApp.CopyPasteType.PASTE_VALUES,
          false
        ); // во второй колонке меняет формулу на значение
        destination2.copyTo(
          destination2,
          SpreadsheetApp.CopyPasteType.PASTE_VALUES,
          false
        ); // в третьей колонке меняет формулу на значение
        destination3.copyTo(
          destination3,
          SpreadsheetApp.CopyPasteType.PASTE_VALUES,
          false
        ); // в пятой колонке меняет формулу на значение
        destination4.copyTo(
          destination4,
          SpreadsheetApp.CopyPasteType.PASTE_VALUES,
          false
        ); // в восьмой колонке меняет формулу на значение
        SpreadsheetApp.getActive().toast('Готово');
      }
    }
    Ответ написан
    4 комментария
  • Как передать аргументы в функцию, вызванную из меню?

    oshliaer
    @oshliaer Куратор тега Google Apps Script
    Google Products Expert
    Допустим, у вас есть описание меню для некоторой функции

    var MENU = [
      {
        caption: 'Пункт меню 1',
        functionName: 'itemMenu',
      },
      {
        caption: 'Пункт меню 2',
        functionName: 'itemMenu',
      },
      {
        caption: 'Пункт меню 3',
        functionName: 'itemMenu',
      },
    ];


    Очевидно, что вы помимо основного меню сможете построить и меню из этого массива

    function onOpen() {
      var ui = SpreadsheetApp.getUi();
    
      var menu = ui.createMenu('Test');
    
      MENU.forEach(function(item, i) {
        menu.addItem(item.caption, item.functionName + i);
      });
    
      menu.addToUi();
    }


    Положим, что itemMenu работает как-то так

    function itemMenu(e) {
      var caption = e.item.caption;
      var order = e.order;
      Browser.msgBox(
        Utilities.formatString('Был нажат %sй пункт меню: %s', order + 1, caption)
      );
    }


    Тогда можно передать глобальному контексту обернутые колбэки с заданным аргументом

    (function(self) {
      MENU.forEach(function(item, i) {
        self[item.functionName + i] = function() {
          return self[item.functionName]({ item: item, order: i });
        };
      });
    })(this);


    Полный листинг тут

    5e5bcdbc5dd9e315037179.png
    Ответ написан
    5 комментариев
  • Как посчитать разницу значений ячеек?

    PolarBearGG
    @PolarBearGG
    I know that I know nothing
    =arrayformula(a1:A-B1:B)
    Ответ написан
    Комментировать
  • Управление блоком полевых транзисторов по одному проводу, возможно ли такое?

    Если нужны только выходы (управление транзистором, реле, светодиодом) то дешевле всего применять сдвиговый регистр (первая нагугленная статья: robocraft.ru/blog/arduino/519.html ). Управление - SPI.
    Если впоследствии нужен будет полноценный порт, который может работать как на вход, так и на выход, то вот статья ( we.easyelectronics.ru/part/i2c-rasshiritel-portov-... ) про i2c расширитель портов.
    Для 1wire что-то подобное было, но сходу не смог найти.
    Ответ написан
    Комментировать
  • Как сделать проверку по определенному столбцу?

    oshliaer
    @oshliaer Куратор тега Google Apps Script
    Google Products Expert
    Если без объяснений кода, то

    function onEdit() {
       run2();
    }
    
    function run2() {
      /* Remove dash */
      var sheet = SpreadsheetApp.getActiveSheet();
      if (sheet.getName() === 'Журнал вода данных') return;
      var archive = SpreadsheetApp.getActive().getSheetByName('Журнал вода данных');
    
      var action = function(values, i, i2) {
        var data = values.slice(i, i + i2);
        archive
          .getRange(archive.getLastRow() + 1, 1, data.length, data[0].length)
          .setValues(data);
      };
    
      var condition = function(values, i) {
        var row = values[i];
        return (
          i > 0 && row[0] !== '' && row[1] !== '' && row[3] !== '' && row[5] !== ''
        );
      };
    
      deleteRowsByConditional_(sheet, condition, action);
    }
    
    function deleteRowsByConditional_(sheet, condition, action) {
      sheet
        .getDataRange()
        .getValues()
        .forEach(
          function(_, i, arr) {
            var j = arr.length - i - 1;
            if (this.condition.apply(null, [arr, j])) {
              this.isContinue++;
              if (j > 0) return;
            }
            if (this.isContinue > 0) {
              var prevPos = j + 1; // It's reversed
              if (action) action(arr, prevPos, this.isContinue);
              this.sheet.deleteRows(prevPos + 1, this.isContinue);
              this.isContinue = 0;
              return;
            }
            return;
          },
          { sheet: sheet, condition: condition, isContinue: 0 }
        );
    }


    Будет работать на любом листе вашей Таблицы. Можно подключить run2() к меню.

    Ссылка на видео https://www.facebook.com/oshliaer/videos/258791787...

    Ссылка на сниппет https://github.com/contributorpw/google-apps-scrip...
    Ответ написан
    Комментировать
  • Как уменьшить время ответа по COM-порту Arduino в Java?

    @vanyamba-electronics
    При выводе данных на терминал по COM-порту везде применяется кэширование, поскольку компьютер не может ждать столько времени, выводя символ за символом в медленный COM-порт.
    Алгоритм кэширования в свою очередь выводит данные построчно. То есть отправляет данные на терминал, только получив символ '\n'.
    Чтобы отправить данные немедленно, нужно вызвать функцию flush().
    Ответ написан
    Комментировать
  • Какой физический смысл импульса?

    @caballero
    Программист
    импуль -фундаментальное понятие. так же как время энергия пространство
    у него нет смысла. Импуль просто есть и все. и он не обязательно связат с телами массой и движением - у фотона например тоже есть импульс
    Ответ написан
    6 комментариев
  • Как сделать формулу "массовой"?

    oshliaer
    @oshliaer Куратор тега Google Sheets
    Google Products Expert
    Никак. Есть формулы, которые поддерживают массивы и которые поддерживаются в массивах. А есть такие как эта.
    Ответ написан
    3 комментария