Основы программирования: списки

Копия List_Cat
"Список - это упорядоченный набор объектов (компонентов). Список может объединять разные (возможно, не связанные между собой) объекты под одним именем. К примеру, список может представлять собой сочетание векторов, матриц, таблиц данных и даже других списков" (Роберт Кабаков. Анализ и визуализация данных на языке R). Главное преимущество списков связано с их гибкостью. Во-первых, как уже упомянуто, они могут включать данные и объекты разных типов. Во-вторых, размер списков не задается при их создании и может меняться в соответствии с интересами исследователя. Эти две особенности отличают списки от векторов. Третьим, но менее важным отличием является то, что доступ к элементам списков возможно как по индексам, так и по ключевым словам. В этом смысле списки в R объединяют свойства как списков, так и словарей (если использовать Python-овскую терминологию).
Именно списки очень удобно использовать в работе циклов - добавление новых элементов будет идти не по пути перезаписи списка, а по пути его расширения. Благодаря использованию циклов, условных операторов и списков открываются широкие возможности решения творческих задач как в рамках программирования в целом, так и в рамках анализа данных в частности.
Создание списков
Список создается с помощью функции list(). При этом есть два варианта - с указанием имен и без него. Если при создании имена указываются (см. 1 строку синтаксиса), то доступ к соответствующему элементу может осуществляться как с помощью индексирования, так и с помощью самих имен. Если же имена не указываются (см. 6 строку синтаксиса), то остается только доступ с помощью индексирования.
1
2
3
4
5
6
7
8
  > test <- list(money=c(300,400,500),name=c("Аня","Люда","Таня"))
  > test$money
  [1] 300 400 500
  > test[[2]]
  [1] "Аня"  "Люда" "Таня"
  > testNew <- list(c(200,300,400),c("Коля","Паша","Вася"))
  > testNew[[2]]
  [1] "Коля" "Паша" "Вася"
Как видно, первый список (test), включает два элемента: числовой вектор с именем "money" и текстовый с именем "name". Далее продемонстрированы способы доступа к его элементам с помощью имени и с помощью индекса. Следующий список (testNew) идентичен первому с тем отличием, что его элементы не содержат имен.
Рассмотрим еще один пример, в котором список еще более похож на склад различных элементов:
 9
10
11
12
13
14
15
16
17
18
19
20
21
  > dolla <- c(300,400,500)
  > ppl <- c("Аня","Люда","Таня")
  > someData <- data.frame(dolla,ppl)
  > testNew <- list(df=someData,c(T,T,F),end=88)
  > testNew[[2]][3]
  [1] FALSE
  > testNew$df
    dolla  ppl
  1   300  Аня
  2   400 Люда
  3   500 Таня
  > testNew[[3]]
  [1] 88
В данном случае сначала создается фрейм данных someData, после чего он и другие данные записываются в список. При этом два элемента списка имеют имена, один - нет.
Доступ к элементам списка
Как уже было показано, доступ к элементам списка осуществляется с помощью указания индекса в квадратных скобках, а также с помощью указания имени элемента после знака "$" (конечно если элемент имеет имя).
При использовании индекса можно использовать как одинарные квадратные скобки, так и двойные. Различие в том, что в первом случае возвращаемый объект будет новым списком с одним элементом, во втором - будет возвращен тот тип объекта, к которому мы возвращаемся.
Чтобы понять о чем идет речь рассмотрим пример:
22
23
  > itIsNewList <- testNew[1]
  > itIsNewDataFrame <- testNew[[1]]
В первой строке предыдущего синтаксиса создается новый список с одним элементом - фреймом данных. Во второй строке будет получен сам фрейм данных, а не список.
При использовании ключевых слов для доступа к элементам списка, они указываются либо после знака "$", либо в квадратных скобках (само слово при этом указывается в кавычках):
24
25
26
  > oneNumber <- testNew$end
  > oneNumber <- testNew["end"]
  > oneNumber <- testNew[["end"]]
Первый способ ведет к созданию скаляра, второй - к созданию нового списка с одним элементом-скаляром, третий - к созданию скаляра.
Добавление и удаление элементов списка
Новые элементы списка добавляются с помощью присваивания. При этом указывается индекс или имя элемента, определяющие куда будет записана информация. Здесь возможны следующие варианты: а) если указывается индекс уже имеющегося элемента списка (например, индекс 3 для списка с тремя элементами), то новая инфомация записывается вместо старой; б) то же самое справедливо, когда используется имя уже имеющегося элемента; в) если указывается индекс, элемента которого еще нет (например, индекс 5 для списка с тремя элементами), то будет соответствующая информация появится на указанной позиции, а все предыдущие элементы (в нашем случае 4 элемент) будут обозначены как не имеющие данных (NULL); г) если при создании используется еще не существующее имя, то соответствующий элемент с этим именем будет записан на новую свободную позицию, созданную в конце списка (в нашем случае это будет позиция с индексом 6).
Рассмотрим синтаксис для каждого из вариантов:
27
28
29
30
31
32
33
34
35
36
37
38
  > testNew[[3]] <- 99 # вариант а
  > testNew[[3]]
  [1] 99
  > testNew$end <- 111 # вариант б
  > testNew[[3]]
  [1] 111
  > testNew[[5]] <- c(88,99) # вариант в
  > testNew[[4]]
  NULL
  > testNew$last <- FALSE # вариант г
  > testNew[[6]]
  [1] FALSE
Удаляются элементы с помощью присваивания им значения NULL (можно прописать как с помощью индекса, так и с помощью имени). При этом если удаляется любой элемент кроме последнего, то все остальные сдвигаются влево. Например, если в списке из пяти элементов удалить третий, то первый и второй останутся на своих местах, четвертый станет третим (займет место удаленного элемента), а пятый - четвертым.
В предыдущем примере удалим четвертый пустой элемент:
39
40
41
42
43
  > length(testNew) # проверяем длину объекта (количество элементов)
  [1] 6
  > testNew[[4]] <- NULL # удаляем пустой элемент
  > length(testNew) # опять проверяем длину объекта
  [1] 5
В завершение рассмотрим синтаксис c использованием списков из реальной практики:
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
  > for (i in 1:17) {
      test <- allDatatest[which(allDatatest$godNew == filt[i]) , ]
      testNew <- data.frame(c(1:length(test$godNew)))
      for (j in (1:31)) {
        if (mean(test[,j])!=-999 & sd(test[,j], na.rm=T)!= 0) {
          testNew <- cbind(testNew,test[,j])
          names(testNew)[length(testNew)] <- nameS[j]
        }
      }
      testNew$godNew <- NULL
      testNew$c.1.length.test.godNew.. <- NULL
      matr <- as.matrix(testNew)
      matr[matr==-999]<-NA
      testNew <- as.data.frame(matr)
      listForPrestVar[[i]] <- testNew
    } 
Задача этого синтаксиса подготовка фреймов данных для каждого года (testNew) исследования и их запись в список listForPrestVar (строка синтаксиса 58). После завершения цикла список будет состоять из 17 элементов. В дальнейшем он используется для обработки каждого фрейма данных по отдельности.

статью подготовил кандидат социологических наук Сергей Дембицкий

Data science (3)
Europe (2)
Geopolitics (2)
Infographics (1)
R (26)
Russia (2)
SPSS (2)
Ukraine (2)
Акционализм (1)
Анализ данных (27)
Аномия (1)
Выборка (1)
Выступления (3)
Геополитика (12)
Гражданское общество (2)
Демократизация (1)
Европа (4)
Интернет ресурсы (1)
Инфографика (8)
Исследовательские дизайны (1)
Историческая социология (10)
История социологии (5)
Киберспорт (1)
Книги (7)
Массивы (3)
Методология социальных исследований (1)
Методология социологических исследований (2)
Научная жизнь (3)
Новости (6)
Обратная связь (1)
Персоналии (3)
Православные конфессии в Украине (1)
Президентская власть (1)
Психологический дистресс (18)
Психология (5)
Публицистика (2)
Революция (1)
Результаты исследований (28)
Религия (3)
Россия (2)
Согласование концептов (4)
Социальная гетерогенность (1)
Социальная работа (1)
Социологическая теория (6)
Социологические тесты (1)
Социологическое образование (5)
Теория конфликта (2)
Теория социального измерения (8)
Украина (9)
Учебные планы (2)
Философия (1)
Шкалирование (36)
Экономика (1)
Эмпирическая социология (46)

free counters
Яндекс.Метрика