Нельзя использовать мутирующий член & hellip; потому что добавить?

Дольше, чем я ожидал:

>>> df
                samples  subject  trial_num
0  [-0.07, -2.9, -2.44]        1          1
1   [-1.52, -0.35, 0.1]        1          2
2  [-0.17, 0.57, -0.65]        1          3
3  [-0.82, -1.06, 0.47]        2          1
4   [0.79, 1.35, -0.09]        2          2
5   [1.17, 1.14, -1.79]        2          3
>>>
>>> s = df.apply(lambda x: pd.Series(x['samples']),axis=1).stack().reset_index(level=1, drop=True)
>>> s.name = 'sample'
>>>
>>> df.drop('samples', axis=1).join(s)
   subject  trial_num  sample
0        1          1   -0.07
0        1          1   -2.90
0        1          1   -2.44
1        1          2   -1.52
1        1          2   -0.35
1        1          2    0.10
2        1          3   -0.17
2        1          3    0.57
2        1          3   -0.65
3        2          1   -0.82
3        2          1   -1.06
3        2          1    0.47
4        2          2    0.79
4        2          2    1.35
4        2          2   -0.09
5        2          3    1.17
5        2          3    1.14
5        2          3   -1.79

Если вам нужен последовательный индекс, вы можете применить reset_index(drop=True) к результату.

update:

>>> res = df.set_index(['subject', 'trial_num'])['samples'].apply(pd.Series).stack()
>>> res = res.reset_index()
>>> res.columns = ['subject','trial_num','sample_num','sample']
>>> res
    subject  trial_num  sample_num  sample
0         1          1           0    1.89
1         1          1           1   -2.92
2         1          1           2    0.34
3         1          2           0    0.85
4         1          2           1    0.24
5         1          2           2    0.72
6         1          3           0   -0.96
7         1          3           1   -2.72
8         1          3           2   -0.11
9         2          1           0   -1.33
10        2          1           1    3.13
11        2          1           2   -0.65
12        2          2           0    0.10
13        2          2           1    0.65
14        2          2           2    0.15
15        2          3           0    0.64
16        2          3           1   -0.10
17        2          3           2   -0.76
2
задан user28434 16 January 2019 в 13:57
поделиться

4 ответа

Функции возвращают неизменные значения. Это так, как это происходит в Swift. Если вы хотите, чтобы он был изменяемым, вы должны сначала сохранить его в var.

Однако, вы можете использовать + для объединения Array с любым Sequence. Поэтому, если filteredApps является Array, это должно сработать:

    let filteredDataOpt: [TimeSeriesEntry?] = filteredApps
        .map { data in
            let isInDate = dates.contains { date in
                guard let d = date else {
                    return false
                }
                return Calendar.current.isDate(d, equalTo: data.date, toGranularity: Calendar.Component.day)
            }
            return isInDate ? self.timeSeriesData(appData: data) : nil
    } + self.locationsData.map { data in
        let isInDate = dates.contains { date in
            guard let d = date else {
                return false
            }
            return Calendar.current.isDate(d, equalTo: data.date, toGranularity: Calendar.Component.day)
        }
        return isInDate ? self.timeSeriesData(locationData: data) : nil
    }
    let filteredData = filteredDataOpt.compactMap { [110] }

Есть несколько других вещей, которые мы можем сделать, чтобы очистить и этот код. Мы можем вычленить тест даты:

    func isValid(_ candidate: Date) -> Bool {
        return dates.contains { date in
            guard let d = date else {
                return false
            }
            return Calendar.current.isDate(d, equalTo: candidate, toGranularity: Calendar.Component.day)
        }
    }

    let filteredDataOpt: [TimeSeriesEntry?] = filteredApps
        .map { data in
            return isValid(data.date) ? self.timeSeriesData(appData: data) : nil
    } + self.locationsData.map { data in
        return isValid(data.date) ? self.timeSeriesData(locationData: data) : nil
    }
    let filteredData = filteredDataOpt.compactMap { [111] }

В зависимости от ваших данных, может быть лучше предварительно рассчитать допустимые диапазоны Date:

    let calendar = Calendar.current
    let dayRanges: [Range<Date>] = dates.lazy.compactMap({ [112] }).map({ date in
        let start = calendar.startOfDay(for: date)
        let end = calendar.date(byAdding: .day, value: 1, to: start)!
        return start ..< end
    })

    func isValid(_ candidate: Date) -> Bool {
        return dayRanges.contains(where: { [112].contains(candidate) })
    }

Мы также можем разделить фильтрация от трансформера. Это позволяет нам исключить использование compactMap:

    let filteredData = Array(filteredApps.lazy.filter({ isValid([113].date) }).map(self.timeSeriesData))
        + locationsData.lazy.filter({ isValid([113].date) }).map(self.timeSeriesData)

Или мы могли бы использовать compactMap дважды:

    let filteredData = filteredApps.compactMap({ isValid([114].date) ? self.timeSeriesData(appData: [114]) : nil })
        + locationsData.compactMap({ isValid([114].date) ? self.timeSeriesData(locationData: [114]) : nil })
0
ответ дан rob mayoff 16 January 2019 в 13:57
поделиться

Ваша проблема может быть сведена к следующему:

let data = [1, 2, 3]
let data2 = [4, 5, 6]

let filteredData: [Int] = data
    .map { [110] }
    .append(contentsOf: data2.map { [110] })

Решение состоит в том, чтобы использовать конкатенацию вместо append:

let data = [1, 2, 3]
let data2 = [4, 5, 6]

let filteredData: [Int] = data
    .map { [111] }
    + data2.map { [111] }

Для объяснения это похоже на :

let a: Int = 0
let b = a += 1 // this is append
let c = (a + 1) += 1 // this is append with a temporary expression

(вы добавляете что-то, что немедленно отбрасывается, а значение не сохраняется в c).

, что, очевидно, следует сделать как

let a: Int = 0
let b = a + 1

. Обратите внимание, что даже если бы вы могли append использовать временное возвращаемое значение, append не имеет возвращаемого значения, а ваш результат, назначенный filteredDataOpt, быть Void.

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

0
ответ дан Sulthan 16 January 2019 в 13:57
поделиться

Проблема в том, что метод append(contentsOf:) мутирует, и возвращаемый элемент любой функции в swift по умолчанию неизменен.

Вот почему вы не можете вызвать метод append(contentsOf:) для массива, возвращенного методом map.

Лучше вы можете использовать не мутантный метод appending(contentsOf:) для своего кода.

Таким образом, ваш код будет:

// next, select only entries in range
let filteredDataOpt: [TimeSeriesEntry?] = filteredApps
    .map { data in
        let isInDate = dates.contains { date in
            guard let d = date else {
                return false
            }
            return Calendar.current.isDate(d, equalTo: data.date, toGranularity: Calendar.Component.day)
        }
        return isInDate ? timeSeriesDataFromAppData(data) : nil
    }.appending(contentsOf: locationsData.map { data in
        let isInDate = dates.contains { date in
            guard let d = date else {
                return false
            }
            return Calendar.current.isDate(d, equalTo: data.date, toGranularity: Calendar.Component.day)
        }
        return isInDate ? timeSeriesDataFromLocationData(data) : nil
    })
0
ответ дан Sulthan 16 January 2019 в 13:57
поделиться

Не ответ на ваш вопрос, но это сработает

var filteredDataOpt: [TimeSeriesEntry?] = filteredApps
        .map { data in
            let isInDate = dates.contains { date in
                guard let d = date else {
                    return false
                }
                return Calendar.current.isDate(d, equalTo: data.date, toGranularity: Calendar.Component.day)
            }
            return isInDate ? timeSeriesDataFromAppData(data) : nil
        }
filteredDataOpt.append(contentsOf: locationsData.map { data in
            let isInDate = dates.contains { date in
                guard let d = date else {
                    return false
                }
                return Calendar.current.isDate(d, equalTo: data.date, toGranularity: Calendar.Component.day)
            }
            return isInDate ? timeSeriesDataFromLocationData(data) : nil})
0
ответ дан Joakim Danielson 16 January 2019 в 13:57
поделиться
Другие вопросы по тегам:

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