File: simplify.R

package info (click to toggle)
r-cran-jsonlite 1.9.1%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,340 kB
  • sloc: ansic: 3,792; sh: 9; makefile: 6
file content (139 lines) | stat: -rw-r--r-- 4,331 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
simplify <- function(x, simplifyVector = TRUE, simplifyDataFrame = TRUE, simplifyMatrix = TRUE,
  simplifyDate = simplifyVector, homoList = TRUE, flatten = FALSE, columnmajor = FALSE,
  simplifySubMatrix = simplifyMatrix) {

  #This includes '[]' and '{}')
  if (!is.list(x) || !length(x)) {
    return(x)
  }

  # list can be a dataframe recordlist
  if (isTRUE(simplifyDataFrame) && is.recordlist(x)) {
    mydf <- simplifyDataFrame(x, flatten = flatten, simplifyMatrix = simplifySubMatrix)
    if(isTRUE(simplifyDate) && is.data.frame(mydf) && is.datelist(mydf)){
      return(parse_date(mydf[["$date"]]))
    }
    return(mydf)
  }

  # or a scalar list (atomic vector)
  if (isTRUE(simplifyVector) && is.null(names(x)) && is.scalarlist(x)) {
    return(list_to_vec(x))
  }

  # apply recursively
  out <- lapply(x, simplify, simplifyVector = simplifyVector, simplifyDataFrame = simplifyDataFrame,
    simplifyMatrix = simplifySubMatrix, columnmajor = columnmajor, flatten = flatten)

  # fix for mongo style dates turning into scalars *after* simplifying
  # only happens when simplifyDataframe=FALSE
  if(isTRUE(simplifyVector) && is.scalarlist(out) && all(vapply(out, inherits, logical(1), "POSIXt"))){
    return(structure(list_to_vec(out), class=c("POSIXct", "POSIXt")))
  }

  # test for matrix. Note that we have to take another look at x (before
  # list_to_vec on its elements) to differentiate between matrix and vector.
  if (isTRUE(simplifyMatrix) && isTRUE(simplifyVector) && is.matrixlist(out) && all(unlist(vapply(x, is.scalarlist, logical(1))))) {
    if(isTRUE(columnmajor)){
      return(do.call(cbind, out))
    } else {
      #this is currently the default
      return(do.call(rbind, out))
    }
  }

  # Simplify higher arrays
  if (isTRUE(simplifyMatrix) && is.arraylist(out)){
    if(isTRUE(columnmajor)){
      return(array(
        data = do.call(cbind, out),
        dim = c(dim(out[[1]]), length(out))
      ));
    } else {
      #this is currently the default
      return(array(
        data = do.call(rbind, lapply(out, as.vector)),
        dim = c(length(out), dim(out[[1]]))
      ));
    }
  }

  # try to enfoce homoList on unnamed lists
  if (isTRUE(homoList) && is.null(names(out))) {
    # coerse empty lists, caused by the ambiguous fromJSON('[]')
    isemptylist <- vapply(out, identical, logical(1), list())
    if (any(isemptylist) & !all(isemptylist)) {
      # if all the others look like data frames, coerse to data frames!
      if (all(vapply(out[!isemptylist], is.data.frame, logical(1)))) {
        for (i in which(isemptylist)) {
        out[[i]] <- data.frame()
        }
        return(out)
      }

      # if all others look like atomic vectors, unlist all
      if (all(vapply(out[!isemptylist], function(z) {
        isTRUE(is.vector(z) && is.atomic(z))
      }, logical(1)))) {
        for (i in which(isemptylist)) {
        out[[i]] <- vector(mode = typeof(out[[which(!isemptylist)[1]]]))
        }
        return(out)
      }
    }
  }

  # convert date object
  if( isTRUE(simplifyDate) && is.datelist(out) ){
    return(parse_date(out[["$date"]]))
  }

  # return object
  return(out)
}

is.matrixlist <- function(x) {
  isTRUE(is.list(x)
    && length(x)
    && is.null(names(x))
    && all(vapply(x, is.atomic, logical(1)))
    && all_identical(vapply(x, length, integer(1)))
    #&& all_identical(vapply(x, mode, character(1))) #this fails for: [ [ 1, 2 ], [ "NA", "NA" ] ]
  );
}

is.arraylist <- function(x) {
  isTRUE(is.list(x)
    && length(x)
    && is.null(names(x))
    && all(vapply(x, is.array, logical(1)))
    && all_identical(vapply(x, function(y){paste(dim(y), collapse="-")}, character(1)))
  );
}

is.datelist <- function(x){
  isTRUE(is.list(x)
     && identical(names(x), "$date")
     && (is.numeric(x[["$date"]]) || is.character(x[["$date"]]))
  );
}

parse_date <- function(x){
  if(is.numeric(x)){
    return(structure(x/1000, class=c("POSIXct", "POSIXt")))
  } else if(is.character(x)) {
    #tz is not vectorized, so assume all() are the same
    is_utc <- ifelse(all(grepl("Z$", x)), "UTC", "")
    return(as.POSIXct(strptime(x, format = '%Y-%m-%dT%H:%M:%OS', tz = is_utc)))
  } else {
    return(x)
  }
}

all_identical <- function(x){
  if(!length(x)) return(FALSE)
  for(i in x){
    if(x[1] != i) return(FALSE)
  }
  return(TRUE)
}