'Create list of arrays that contain specific element

I need to create a function that searches if certain string is within an array and create a list with all the elements (lists) that contain it. For example:

word = 'busy'
array = [[['99', 'Normal', [], ['busy', '0'], 28016.2, 'working', '1']],[['F27', 'Normal', [], ['free', '0'], 28016.537865230806, 'working', '1']]]

So my output should be:

[['99', 'Normal', [], ['busy', '0'], 362.01, 'working', '1']]

But I only get that the validation that says that the string doesn't exist, when it obviously does. Here's the code:

array = [[['99', 'Normal', [], ['busy', '0'], 28016.2, 'working', '1']],[['F27', 'Normal', [], ['free', '0'], 28016.537865230806, 'working', '1']]]

def searchBusyWorkers(array):
    busy = []
    for x in array:
        if 'busy' in x:
            ind = x.index('busy')
            busy.append(array[ind])
            return busy
        else:
            return "No workers have that condition."


Solution 1:[1]

'busy' in x fails because "busy" is nested one level deeper. In other words, there is no 'busy' in x but there is a sub-array in x that contains the string "busy".

Since you mention that 'busy' will always be at a particular index, you need to unpack to get the sub-array and then check that index -

for x in array:
    elements, *_ = x
    if 'busy' in elements[3]:
        print(x)

output

[['99', 'Normal', [], ['busy', '0'], 28016.2, 'working', '1']]

Solution 2:[2]

I would do it this way:

array = [[['99', 'Normal', [], ['busy', '0'], 28016.2, 'working', '1']],[['F27', 'Normal', [], ['free', '0'], 28016.537865230806, 'working', '1']]]

def searchforword(word, array):
    return([y for x in array for y in x for i in y if word in str(i)])

Results:

word = 'busy'
print(searchforword(word, array))
[['99', 'Normal', [], ['busy', '0'], 28016.2, 'working', '1']]
word = 'free'
print(searchforword(word, array))
[['F27', 'Normal', [], ['free', '0'], 28016.537865230806, 'working', '1']]

Solution 3:[3]

This should work

new_list = []
for i in range(len(array)):
  for j in (array[i]):
    if isinstance(j, list):
      try:
        for r in j:
          if word in r:
            new_list.append(array[i])
      except:
        ...
    if word in j or word in array[i]: #update
         new_list.append(array[i])

print(*new_list) # Update

Output:

[['99', 'Normal', [], ['busy', '0'], 28016.2, 'working', '1']]

Solution 4:[4]

This can work but it involves changing the contents of add_y.

library(rlang)
library(magrittr)
library(stringr)

add_y <- function(y) {
  fn <- expr(function(x) {
    x+!!y
  })
  fn <- deparse(fn) %>% str_c(collapse = "")
  fn <- eval(parse(text = fn))
}

add_4 <- add_y(4)

dput(add_4)
#> function (x) 
#> {
#>     x + 4
#> }

Created on 2021-12-24 by the reprex package (v2.0.1)

Solution 5:[5]

You could construct a dput replacement that generated code that creates a function like add_4, but it wouldn't deparse the way you want:

dput_with_env <- function(f) {
  fn <- deparse(f, control = c("keepNA", "keepInteger", 
                               "niceNames", "showAttributes"))
  env <- as.list(environment(f))
  cat("local({ f =\n")
  cat(fn, sep = "\n")
  cat("\nenvironment(f) <- list2env(\n")
  dput(env)
  cat(")\nf})")
}

add_y <- function(y) {
  function(x) {
    x + y
  }
}
add_4 <- add_y(4)

dput_with_env(add_4)
#> local({ f =
#> function (x) 
#> {
#>     x + y
#> }
#> 
#> environment(f) <- list2env(
#> list(y = 4)
#> )
#> f})

Created on 2021-12-24 by the reprex package (v2.0.1)

This assumes that the environment of add_4 is quite simple, so the parent of its environment can be the environment in place when you evaluate the code. We can try it out:

newfn <- local({ f =
function (x) 
{
   x + y
}
environment(f) <- list2env(
list(y = 4)
)
f})

newfn
#> function (x) 
#> {
#>    x + y
#> }
#> <environment: 0x7f9a1b5e2318>
newfn(1)
#> [1] 5

Created on 2021-12-24 by the reprex package (v2.0.1)

Solution 6:[6]

Not with a dput(), no. The dput() function will not create text representations of environments.

If you want to save the function, you could do

save(add_4, file="add4.Rdata")

and then in another R session

load("add4.Rdata")

That will capture all the enclosed values and your function will behave as it did before

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Mortz
Solution 2 user56700
Solution 3
Solution 4 jpdugo17
Solution 5
Solution 6 MrFlick