r - आर का उपयोग करके संरचना को संरक्षित करते हुए एक नेस्टेड सूची से सभी संयोजन कैसे बनाएं?




list recursion (3)

नेस्टेड सूची को देखते हुए, नेस्टेड लिस्ट की संरचना को संरक्षित करते हुए, इसके तत्वों से सभी संभावित सूचियों का निर्माण कैसे करें?

नेस्टेड सूची:

l = list(
    a = list(
        b = 1:2
    ),
    c = list(
        d = list(
            e = 3:4,
            f = 5:6
        )
    ),
    g = 7
)

वांछित आउटपुट: संरचना के संरक्षण के दौरान l के तत्वों के सभी संभावित संयोजन, उदाहरण के लिए:

# One possible output:
list(
    a = list(
        b = 1
    ),
    c = list(
        d = list(
            e = 3,
            f = 5
        )
    ),
    g = 7
)

# Another possible output:
list(
    a = list(
        b = 1
    ),
    c = list(
        d = list(
            e = 4,
            f = 5
        )
    ),
    g = 7
)

मेरा दृष्टिकोण अब तक है:

  1. सूची को समतल करें (जैसे, इस उत्तर में चर्चा की गई)
  2. expand.grid() और एक मैट्रिक्स प्राप्त करें जहां प्रत्येक पंक्ति एक अद्वितीय संयोजन का प्रतिनिधित्व करती है
  3. परिणामी मैट्रिक्स की प्रत्येक पंक्ति को पार्स करें और नियमित अभिव्यक्तियों का उपयोग करके names() से संरचना का पुनर्निर्माण करें

मैं कम बोझिल दृष्टिकोण की तलाश कर रहा हूं क्योंकि मुझे कोई गारंटी नहीं है कि सूची तत्वों के नाम नहीं बदलेंगे।


बेन न्यूटज़र के शानदार उत्तर और जोरिस चाऊ की शानदार टिप्पणी को मिलाकर, यह उत्तर एक-लाइनर बन जाएगा:

apply(expand.grid(data.frame(l)), 1L, relist, skeleton = rapply(l, head, n = 1L, how = "list")) 

यह कई तत्वों के साथ सूचियों की एक सूची बनाता है जितनी पंक्तियाँ विस्तार से वापस expand.grid()expand.grid() । परिणाम बेहतर str() के आउटपुट से दिखाई देता है:

str(apply(expand.grid(data.frame(l)), 1L, relist, skeleton = rapply(l, head, n = 1L, how = "list")))
List of 16
 $ :List of 3
  ..$ a:List of 1
  .. ..$ b: num 1
  ..$ c:List of 1
  .. ..$ d:List of 2
  .. .. ..$ e: num 3
  .. .. ..$ f: num 5
  ..$ g: num 7
 $ :List of 3
  ..$ a:List of 1
  .. ..$ b: num 2
  ..$ c:List of 1
  .. ..$ d:List of 2
  .. .. ..$ e: num 3
  .. .. ..$ f: num 5
  ..$ g: num 7
...
...
...
 $ :List of 3
  ..$ a:List of 1
  .. ..$ b: num 2
  ..$ c:List of 1
  .. ..$ d:List of 2
  .. .. ..$ e: num 4
  .. .. ..$ f: num 6
  ..$ g: num 7

बेन न्यूटज़र और जॉरिस चाऊ के शानदार उत्तरों को एक साथ रखते हुए, हमारे पास एक नेस्टेड सूची से सभी संभावित संयोजनों को बनाने का एक तरीका है, भले ही कुछ सबलिस्ट घटक असमान लंबाई के हों।

एक समारोह के रूप में एक साथ रखें:

list.combine <- function(input) {
    # Create list skeleton.
    skeleton <- rapply(input, head, n = 1, how = "list")

    # Create storage for the flattened list.
    flattened = list()

    # Flatten the list.
    invisible(rapply(input, function(x) {
        flattened <<- c(flattened, list(x))
    }))

    # Create all possible combinations from list elements.
    combinations <- expand.grid(flattened, stringsAsFactors = FALSE)

    # Create list for storing the output.
    output <- apply(combinations, 1, relist, skeleton = skeleton)

    return(output)
}

नोट: यदि कोई चरित्र प्रकार सबलिस्ट घटकों में मौजूद है, तो सब कुछ एक चरित्र के लिए मजबूर किया जाएगा। उदाहरण के लिए:

# Input list.
l <- list(
    a = "string",
    b = list(
        c = 1:2,
        d = 3
    )
)

# Applying the function.
o <- list.combine(l)

# View the list:
str(o)

# List of 2
#  $ :List of 2
#   ..$ a: chr "string"
#   ..$ b:List of 2
#   .. ..$ c: chr "1"
#   .. ..$ d: chr "3"
#  $ :List of 2
#   ..$ a: chr "string"
#   ..$ b:List of 2
#   .. ..$ c: chr "2"
#   .. ..$ d: chr "3"

इसके चारों ओर एक - धीमी गति से - एक लूप के भीतर निर्भर है जो 1x1 डेटाफ्रेम में डेटा को बनाए रखेगा। डेटाफ्रेम को df[, 1] रूप में एक्सेस करने से इनपुट सूची में तत्व के रूप में मूल प्रकार की लंबाई 1 का वेक्टर मिलेगा। उदाहरण के लिए:

अद्यतन की गई सूची। list.combine() :

list.combine <- function(input) {
    # Create list skeleton.
    skeleton <- rapply(input, head, n = 1, how = "list")

    # Create storage for the flattened list.
    flattened = list()

    # Flatten the list.
    invisible(rapply(input, function(x) {
        flattened <<- c(flattened, list(x))
    }))

    # Create all possible combinations from list elements.
    combinations <- expand.grid(flattened, stringsAsFactors = FALSE)

    # Create list for storing the output.
    output <- list()

    # Relist and preserve original data type.
    for (i in 1:nrow(combinations)) {
        output[[i]] <- retain.element.type(relist(flesh = combinations[i, ], skeleton = skeleton))
    }

    return(output)
}

फिर retain.element.type() :

retain.element.type <- function(input.list) {
    for (name in names(input.list)) {
        # If the element is a list, recall the function.
        if(inherits(input.list[[name]], "list")) {
            input.list[[name]] <- Recall(input.list[[name]])

        # Else, get the first element and preserve the type.
        } else {
            input.list[[name]] <- input.list[[name]][, 1]
        }
    }
    return(input.list)
}

उदाहरण:

# Input list.
l <- list(
    a = "string",
    b = list(
        c = 1:2,
        d = 3
    )
)

# Applying the updated function to preserve the data type.
o <- list.combine(l)

# View the list:
str(o)

# List of 2
#  $ :List of 2
#   ..$ a: chr "string"
#   ..$ b:List of 2
#   .. ..$ c: int 1
#   .. ..$ d: num 3
#  $ :List of 2
#   ..$ a: chr "string"
#   ..$ b:List of 2
#   .. ..$ c: int 2
#   .. ..$ d: num 3

असमान सबलिस्ट लंबाई

यहाँ एक दृष्टिकोण है - Uwe और बेन के उत्तरों पर अनुकूलन - जो मनमाने ढंग से सबलिस्ट लंबाई के लिए भी काम करता है। कॉल करने के बजाय data.frame(l) पर data.frame(l) , पहले एक स्तर की सूची के लिए पहले समतल करें और फिर expand.grid पर expand.grid करें। expand.grid पर expand.grid करें:

## skeleton
skel <- rapply(l, head, n = 1L, how = "list")

## flatten to single level list
l.flat <- vector("list", length = length(unlist(skel)))
i <- 0L

invisible(
    rapply(l, function(x) {
          i <<- i + 1L
          l.flat[[i]] <<- x
        })
)

## expand all list combinations 
l.expand <- apply(expand.grid(l.flat), 1L, relist, skeleton = skel)

str(l.expand)
#> List of 12
#>  $ :List of 3
#>   ..$ a:List of 1
#>   .. ..$ b: num 1
#>   ..$ c:List of 1
#>   .. ..$ d:List of 2
#>   .. .. ..$ e: num 3
#>   .. .. ..$ f: num 5
#>   ..$ g: num 7
#>  ...
#>  ...
#>  $ :List of 3
#>   ..$ a:List of 1
#>   .. ..$ b: num 2
#>   ..$ c:List of 1
#>   .. ..$ d:List of 2
#>   .. .. ..$ e: num 4
#>   .. .. ..$ f: num 7
#>   ..$ g: num 7

डेटा

मैंने डेटा संरचना को थोड़ा संशोधित किया है, ताकि सबलिस्ट घटक e और f असमान लंबाई के हों।

l <- list(
    a = list(
        b = 1:2
    ),
    c = list(
        d = list(
            e = 3:4,
            f = 5:7
        )
    ),
    g = 7
)

## calling data.frame on l does not work
data.frame(l)
#> Error in (function (..., row.names = NULL, check.rows = FALSE, check.names = TRUE, : arguments imply differing number of rows: 2, 3




recursion